forked from rc/aircox
		
	rename
This commit is contained in:
		
							
								
								
									
										187
									
								
								aircox_cms/models.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								aircox_cms/models.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,187 @@
 | 
			
		||||
from django.db import models
 | 
			
		||||
from django.contrib.auth.models import User
 | 
			
		||||
from django.contrib.contenttypes.fields import GenericForeignKey
 | 
			
		||||
from django.contrib.contenttypes.models import ContentType
 | 
			
		||||
from django.utils import timezone
 | 
			
		||||
from django.utils.text import slugify
 | 
			
		||||
from django.utils.translation import ugettext as _, ugettext_lazy
 | 
			
		||||
from django.core.urlresolvers import reverse
 | 
			
		||||
 | 
			
		||||
from django.db.models.signals import post_init, post_save, post_delete
 | 
			
		||||
from django.dispatch import receiver
 | 
			
		||||
 | 
			
		||||
from taggit.managers import TaggableManager
 | 
			
		||||
 | 
			
		||||
class Thread (models.Model):
 | 
			
		||||
    """
 | 
			
		||||
    Object assigned to any Post and children that can be used to have parent and
 | 
			
		||||
    children relationship between posts of different kind.
 | 
			
		||||
 | 
			
		||||
    We use this system instead of having directly a GenericForeignKey into the
 | 
			
		||||
    Post because it avoids having to define the relationship with two models for
 | 
			
		||||
    routing (one for the parent and one for the children).
 | 
			
		||||
    """
 | 
			
		||||
    post_type = models.ForeignKey(ContentType)
 | 
			
		||||
    post_id = models.PositiveIntegerField()
 | 
			
		||||
    post = GenericForeignKey('post_type', 'post_id')
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def __get_query_set (cl, function, model, post, kwargs):
 | 
			
		||||
        if post:
 | 
			
		||||
            model = type(post)
 | 
			
		||||
            kwargs['post_id'] = post.id
 | 
			
		||||
 | 
			
		||||
        kwargs['post_type'] = ContentType.objects.get_for_model(model)
 | 
			
		||||
        return getattr(cl.objects, function)(**kwargs)
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def get (cl, model = None, post = None, **kwargs):
 | 
			
		||||
        return cl.__get_query_set('get', model, post, kwargs)
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def filter (cl, model = None, post = None, **kwargs):
 | 
			
		||||
        return self.__get_query_set('filter', model, post, kwargs)
 | 
			
		||||
 | 
			
		||||
    @classmethod
 | 
			
		||||
    def exclude (cl, model = None, post = None, **kwargs):
 | 
			
		||||
        return self.__get_query_set('exclude', model, post, kwargs)
 | 
			
		||||
 | 
			
		||||
    def save (self, *args, **kwargs):
 | 
			
		||||
        self.post = self.__initial_post
 | 
			
		||||
        super().save(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
    def __str__ (self):
 | 
			
		||||
        return self.post_type.name + ': ' + str(self.post)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Post (models.Model):
 | 
			
		||||
    thread = models.ForeignKey(
 | 
			
		||||
        Thread,
 | 
			
		||||
        on_delete=models.SET_NULL,
 | 
			
		||||
        blank = True, null = True,
 | 
			
		||||
        help_text = _('the publication is posted on this thread'),
 | 
			
		||||
    )
 | 
			
		||||
    author = models.ForeignKey(
 | 
			
		||||
        User,
 | 
			
		||||
        verbose_name = _('author'),
 | 
			
		||||
        blank = True, null = True,
 | 
			
		||||
    )
 | 
			
		||||
    date = models.DateTimeField(
 | 
			
		||||
        _('date'),
 | 
			
		||||
        default = timezone.datetime.now
 | 
			
		||||
    )
 | 
			
		||||
    published = models.BooleanField(
 | 
			
		||||
        verbose_name = _('public'),
 | 
			
		||||
        default = True
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    title = models.CharField (
 | 
			
		||||
        _('title'),
 | 
			
		||||
        max_length = 128,
 | 
			
		||||
    )
 | 
			
		||||
    content = models.TextField (
 | 
			
		||||
        _('description'),
 | 
			
		||||
        blank = True, null = True
 | 
			
		||||
    )
 | 
			
		||||
    image = models.ImageField(
 | 
			
		||||
        blank = True, null = True
 | 
			
		||||
    )
 | 
			
		||||
    tags = TaggableManager(
 | 
			
		||||
        _('tags'),
 | 
			
		||||
        blank = True,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    def detail_url (self):
 | 
			
		||||
        return reverse(self._meta.verbose_name_plural.lower() + '_detail',
 | 
			
		||||
                       kwargs = { 'pk': self.pk,
 | 
			
		||||
                                  'slug': slugify(self.title) })
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        abstract = True
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Article (Post):
 | 
			
		||||
    static_page = models.BooleanField(
 | 
			
		||||
        _('static page'),
 | 
			
		||||
        default = False,
 | 
			
		||||
    )
 | 
			
		||||
    focus = models.BooleanField(
 | 
			
		||||
        _('article is focus'),
 | 
			
		||||
        default = False,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        verbose_name = _('Article')
 | 
			
		||||
        verbose_name_plural = _('Articles')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class RelatedPostBase (models.base.ModelBase):
 | 
			
		||||
    """
 | 
			
		||||
    Metaclass for RelatedPost children.
 | 
			
		||||
    """
 | 
			
		||||
    def __new__ (cls, name, bases, attrs):
 | 
			
		||||
        rel = attrs.get('Relation')
 | 
			
		||||
        rel = (rel and rel.__dict__) or {}
 | 
			
		||||
 | 
			
		||||
        related_model = rel.get('related_model')
 | 
			
		||||
        if related_model:
 | 
			
		||||
            attrs['related'] = models.ForeignKey(related_model)
 | 
			
		||||
 | 
			
		||||
        if not '__str__' in attrs:
 | 
			
		||||
            attrs['__str__'] = lambda self: str(self.related)
 | 
			
		||||
 | 
			
		||||
        return super().__new__(cls, name, bases, attrs)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class RelatedPost (Post, metaclass = RelatedPostBase):
 | 
			
		||||
    related = None
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        abstract = True
 | 
			
		||||
 | 
			
		||||
    class Relation:
 | 
			
		||||
        related_model = None
 | 
			
		||||
        mapping = None          # dict of related mapping values
 | 
			
		||||
        bind_mapping = False    # update fields of related data on save
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    def get_attribute (self, attr):
 | 
			
		||||
        attr = self.Relation.mappings.get(attr)
 | 
			
		||||
        return self.related.__dict__[attr] if attr else None
 | 
			
		||||
 | 
			
		||||
    def save (self, *args, **kwargs):
 | 
			
		||||
        if not self.title and self.related:
 | 
			
		||||
            self.title = self.get_attribute('title')
 | 
			
		||||
 | 
			
		||||
        if self.Relation.bind_mapping:
 | 
			
		||||
            self.related.__dict__.update({
 | 
			
		||||
                rel_attr: self.__dict__[attr]
 | 
			
		||||
                for attr, rel_attr in self.Relation.mapping
 | 
			
		||||
            })
 | 
			
		||||
 | 
			
		||||
            self.related.save()
 | 
			
		||||
 | 
			
		||||
        super().save(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@receiver(post_init)
 | 
			
		||||
def on_thread_init (sender, instance, **kwargs):
 | 
			
		||||
    if not issubclass(Thread, sender):
 | 
			
		||||
        return
 | 
			
		||||
    instance.__initial_post = instance.post
 | 
			
		||||
 | 
			
		||||
@receiver(post_save)
 | 
			
		||||
def on_post_save (sender, instance, created, *args, **kwargs):
 | 
			
		||||
    if not issubclass(sender, Post) or not created:
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
    thread = Thread(post = instance)
 | 
			
		||||
    thread.save()
 | 
			
		||||
 | 
			
		||||
@receiver(post_delete)
 | 
			
		||||
def on_post_delete (sender, instance, using, *args, **kwargs):
 | 
			
		||||
    try:
 | 
			
		||||
        Thread.get(sender, post = instance).delete()
 | 
			
		||||
    except:
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user