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)
|
---|