| 1 | = CookBook - Data Model = |
| 2 | |
| 3 | == A "category" Data Model == |
| 4 | |
| 5 | == Description == |
| 6 | I like to have parent/child categories for my documents and weblog entries. I also am a fan of simplicity. This recipe lets you create new categories, and children of categories while providing an intuitively obvious presentation to the user. A parent category of 'Development' with a child category of 'Python' will be displayed as 'Development :: Python'. Using that example, other data models/content types that utilize this code will have drop-downs in the admin interface with entries of 'Development' and 'Development :: Python' |
| 7 | |
| 8 | == Code == |
| 9 | {{{ |
| 10 | #!python |
| 11 | class Category(models.Model): |
| 12 | name = models.CharField(core=True, maxlength=200) |
| 13 | slug = models.SlugField(prepopulate_from=('name',)) |
| 14 | parent = models.ForeignKey('self', blank=True, null=True, related_name='child') |
| 15 | description = models.TextField(blank=True,help_text="Optional") |
| 16 | |
| 17 | class Admin: |
| 18 | list_display = ('name', '_parents_repr') |
| 19 | |
| 20 | def __str__(self): |
| 21 | p_list = self._recurse_for_parents(self) |
| 22 | p_list.append(self.name) |
| 23 | return self.get_separator().join(p_list) |
| 24 | |
| 25 | def get_absolute_url(self): |
| 26 | if self.parent_id: |
| 27 | return "/tag/%s/%s/" % (self.parent.slug, self.slug) |
| 28 | else: |
| 29 | return "/tag/%s/" % (self.slug) |
| 30 | |
| 31 | def _recurse_for_parents(self, cat_obj): |
| 32 | p_list = [] |
| 33 | if cat_obj.parent_id: |
| 34 | p = cat_obj.parent |
| 35 | p_list.append(p.name) |
| 36 | more = self._recurse_for_parents(p) |
| 37 | p_list.extend(more) |
| 38 | if cat_obj == self and p_list: |
| 39 | p_list.reverse() |
| 40 | return p_list |
| 41 | |
| 42 | def get_separator(self): |
| 43 | return ' :: ' |
| 44 | |
| 45 | def _parents_repr(self): |
| 46 | p_list = self._recurse_for_parents(self) |
| 47 | return self.get_separator().join(p_list) |
| 48 | _parents_repr.short_description = "Tag parents" |
| 49 | |
| 50 | def save(self): |
| 51 | p_list = self._recurse_for_parents(self) |
| 52 | if self.name in p_list: |
| 53 | raise validators.ValidationError("You must not save a category in itself!") |
| 54 | super(Tag, self).save() |
| 55 | }}} |
| 56 | |
| 57 | == See Also == |
| 58 | |
| 59 | http://www.djangoproject.com/documentation/model_api/ |
| 60 | |
| 61 | http://www.djangoproject.com/documentation/models/m2o_recursive/ |
| 62 | |