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