| 1 | from django.db import models
|
|---|
| 2 | from django.db.models import signals
|
|---|
| 3 | from django.dispatch import dispatcher
|
|---|
| 4 |
|
|---|
| 5 | class Category(models.Model):
|
|---|
| 6 | name = models.CharField(maxlength=32)
|
|---|
| 7 | post_count = models.IntegerField(blank=True, default=0)
|
|---|
| 8 |
|
|---|
| 9 | def __unicode__(self):
|
|---|
| 10 | return u"<Category %s '%s' (%s)>" % (self.id, self.name, self.post_count)
|
|---|
| 11 |
|
|---|
| 12 | def __repr__(self):
|
|---|
| 13 | return self.__unicode__()
|
|---|
| 14 |
|
|---|
| 15 | def _m2m_entry(self, entry, increment):
|
|---|
| 16 | if not isinstance(entry, Entry):
|
|---|
| 17 | entry = Entry.objects.get(pk=entry)
|
|---|
| 18 | if entry.status == 'P' and (self.post_count or increment):
|
|---|
| 19 | self.post_count += increment
|
|---|
| 20 | self.save()
|
|---|
| 21 |
|
|---|
| 22 | @staticmethod
|
|---|
| 23 | def m2m_entry(signal, sender, instance, objs=None):
|
|---|
| 24 | if sender == Entry:
|
|---|
| 25 | # instance ---> Category, objs ---> Entry
|
|---|
| 26 | if signal == signals.m2m_clear_items:
|
|---|
| 27 | instance.post_count = 0
|
|---|
| 28 | instance.save()
|
|---|
| 29 | return
|
|---|
| 30 | increment = 1
|
|---|
| 31 | if signal == signals.m2m_remove_items:
|
|---|
| 32 | increment = -1
|
|---|
| 33 | for obj in objs:
|
|---|
| 34 | instance._m2m_entry(obj, increment)
|
|---|
| 35 | else:
|
|---|
| 36 | # instance ---> Entry, objs ---> Category
|
|---|
| 37 | increment = -1
|
|---|
| 38 | if signal == signals.m2m_add_items:
|
|---|
| 39 | increment = 1
|
|---|
| 40 | elif signal == signals.m2m_clear_items:
|
|---|
| 41 | objs = list(instance.categories.all())
|
|---|
| 42 | for obj in objs:
|
|---|
| 43 | if not isinstance(obj, Category):
|
|---|
| 44 | obj = Category.objects.get(pk=obj)
|
|---|
| 45 | obj._m2m_entry(instance, increment)
|
|---|
| 46 |
|
|---|
| 47 |
|
|---|
| 48 | class Entry(models.Model):
|
|---|
| 49 |
|
|---|
| 50 | title = models.CharField(maxlength=64)
|
|---|
| 51 | status = models.CharField(maxlength=1, blank=True, choices=(('P', 'Published'), ('D', 'Draft')), default='D')
|
|---|
| 52 | categories = models.ManyToManyField(Category, blank=True, null=True)
|
|---|
| 53 |
|
|---|
| 54 | def __init__(self, *args, **kw):
|
|---|
| 55 | super(Entry, self).__init__(*args, **kw)
|
|---|
| 56 | self._status = self.status
|
|---|
| 57 |
|
|---|
| 58 | def __unicode__(self):
|
|---|
| 59 | return u"<Post '%s'>" % self.title
|
|---|
| 60 |
|
|---|
| 61 | def __repr__(self):
|
|---|
| 62 | return self.__unicode__()
|
|---|
| 63 |
|
|---|
| 64 | def save(self):
|
|---|
| 65 | super(Entry, self).save()
|
|---|
| 66 | if self.status == 'P' and self._status != 'P':
|
|---|
| 67 | Category.m2m_entry(signals.m2m_add_items, Category, self, list(self.categories.all()))
|
|---|
| 68 | elif self.status != 'P' and self._status == 'P':
|
|---|
| 69 | Category.m2m_entry(signals.m2m_remove_items, Category, self, list(self.categories.all()))
|
|---|
| 70 |
|
|---|
| 71 |
|
|---|
| 72 | # TODO: do not use sender
|
|---|
| 73 | dispatcher.connect(Category.m2m_entry, signal=signals.m2m_add_items, sender=Category)
|
|---|
| 74 | dispatcher.connect(Category.m2m_entry, signal=signals.m2m_remove_items, sender=Category)
|
|---|
| 75 | dispatcher.connect(Category.m2m_entry, signal=signals.m2m_clear_items, sender=Category)
|
|---|
| 76 | dispatcher.connect(Category.m2m_entry, signal=signals.m2m_add_items, sender=Entry)
|
|---|
| 77 | dispatcher.connect(Category.m2m_entry, signal=signals.m2m_remove_items, sender=Entry)
|
|---|
| 78 | dispatcher.connect(Category.m2m_entry, signal=signals.m2m_clear_items, sender=Entry)
|
|---|