This commit is contained in:
bkfox
2015-10-03 14:58:44 +02:00
parent f9d2d47ee6
commit 1a5dcc3eb9
45 changed files with 380 additions and 321 deletions

View File

@ -1,187 +0,0 @@
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