| | 1 | = CookBook - Data Modela = |
| | 2 | |
| | 3 | == Description == |
| | 4 | 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 display as 'Development :: Python'. Using that example, other data models/content types that utilize this code will have drop-downs in the admin interface with entires of 'Development' and 'Development :: Python' |
| | 5 | |
| | 6 | == Code == |
| | 7 | {{{ |
| | 8 | class Category(meta.Model): |
| | 9 | verbose_name_plural = 'Categories' |
| | 10 | module_name = verbose_name_plural.lower() |
| | 11 | fields = ( |
| | 12 | meta.CharField('category_name', maxlength=50), |
| | 13 | meta.CharField('category_parents', maxlength=250, editable=False), |
| | 14 | meta.ForeignKey('self', blank=True, null=True, |
| | 15 | rel_name='parent', related_name='child'), |
| | 16 | ) |
| | 17 | unique_together = (("category_name", "category_parents"),) |
| | 18 | |
| | 19 | def _recurse_for_parents(self, cat_obj): |
| | 20 | p_list = [] |
| | 21 | if cat_obj.parent_id: |
| | 22 | p = cat_obj.get_parent() |
| | 23 | p_list.append(p.category_name) |
| | 24 | more = self._recurse_for_parents(p) |
| | 25 | p_list.extend(more) |
| | 26 | if p_list: |
| | 27 | p_list.reverse() |
| | 28 | return p_list |
| | 29 | |
| | 30 | def get_separator(self): |
| | 31 | return ' :: ' |
| | 32 | |
| | 33 | def _parents_repr(self): |
| | 34 | p_list = self._recurse_for_parents(self) |
| | 35 | return self.get_separator().join(p_list) |
| | 36 | |
| | 37 | def __repr__(self): |
| | 38 | if self.category_parents: |
| | 39 | l = [self.category_parents, self.category_name] |
| | 40 | return self.get_separator().join(l) |
| | 41 | return self.category_name |
| | 42 | |
| | 43 | def _pre_save(self): |
| | 44 | self.category_parents = self._parents_repr() |
| | 45 | |
| | 46 | admin = meta.Admin( |
| | 47 | list_display = ('category_name', 'category_parents'), |
| | 48 | search_fields = ['category_name', 'category_parents'], |
| | 49 | ) |
| | 50 | ordering = ('category_parents', 'category_name') |
| | 51 | }}} |
| | 52 | |
| | 53 | == API Usage == |
| | 54 | Let's fill in some root-level categories: |
| | 55 | {{{ |
| | 56 | >>> from yourpkg.apps.yourapp.models import yourapp |
| | 57 | >>> base_cats = [ |
| | 58 | ... {'category_name': 'Development'}, |
| | 59 | ... {'category_name': 'Systems'}, |
| | 60 | ... {'category_name': 'Management'}, |
| | 61 | ... {'category_name': 'Community'}, |
| | 62 | ... ] |
| | 63 | >>> for cat in base_cats: |
| | 64 | ... new_cat = yourapp.Category(**cat) |
| | 65 | ... new_cat.save() |
| | 66 | >>> |
| | 67 | }}} |
| | 68 | |
| | 69 | Now, let's create some sub categories, examining the dict as we go: |
| | 70 | {{{ |
| | 71 | >>> cat = {'parent_id': 1, 'category_name': 'Python'} |
| | 72 | >>> new_cat = yourapp.Category(**cat) |
| | 73 | >>> new_cat.__dict__ |
| | 74 | {'parent_id': 1, 'id': '', 'category_parents': '', 'category_name': 'Python'} |
| | 75 | >>> new_cat._pre_save() |
| | 76 | >>> new_cat.__dict__ |
| | 77 | {'_parent_cache': Development, 'parent_id': 1, 'id': '', 'category_parents': 'Development', 'category_name': 'Python'} |
| | 78 | >>> new_cat.save() |
| | 79 | >>> new_cat.__dict__ |
| | 80 | {'_parent_cache': Development, 'parent_id': 1, 'id': 5, 'category_parents': 'Development', 'category_name': 'Python'} |
| | 81 | >>> new_cat |
| | 82 | Development :: Python |
| | 83 | }}} |
| | 84 | |
| | 85 | |
| | 86 | Now, let's add a few more and print all the categories: |
| | 87 | {{{ |
| | 88 | >>> cat = {'parent_id': 2, 'category_name': 'Administration'} |
| | 89 | >>> yourapp.Category(**cat).save() |
| | 90 | >>> cat = {'parent_id': 7, 'category_name': 'UNIX'} |
| | 91 | >>> yourapp.Category(**cat).save() |
| | 92 | >>> for cat in yourapp.categories.get_list(): |
| | 93 | ... print cat |
| | 94 | ... |
| | 95 | Community |
| | 96 | Development |
| | 97 | Management |
| | 98 | Systems |
| | 99 | Development :: Python |
| | 100 | Systems :: Administration |
| | 101 | Systems :: Administration :: UNIX |
| | 102 | }}} |
| | 103 | == Usage in Other Data Models == |
| | 104 | {{{ |
| | 105 | class Document(meta.Model): |
| | 106 | fields = ( |
| | 107 | meta.CharField('title', maxlength=200), |
| | 108 | meta.ForeignKey(Category, name='subject', blank=True, null=True), |
| | 109 | ... |
| | 110 | }}} |