Creating Custom Categories#
Django Categories isn’t just for using a single category model. It allows you to create your own custom category-like models with as little or much customization as you need.
Name only#
For many cases, you want a simple user-managed lookup table. You can do this with just a little bit of code. The resulting model will include name, slug and active fields and a hierarchical admin.
Create a model that subclasses
CategoryBase
1from categories.models import CategoryBase 2 3 4class SimpleCategory(CategoryBase): 5 """ 6 A simple of catgorizing example 7 """ 8 9 class Meta: 10 verbose_name_plural = "simple categories"
Create a subclass of CategoryBaseAdmin.
1from django.contrib import admin 2 3from categories.admin import CategoryBaseAdmin 4 5from .models import SimpleCategory 6 7 8class SimpleCategoryAdmin(CategoryBaseAdmin): 9 pass 10 11 12admin.site.register(SimpleCategory, SimpleCategoryAdmin)
Register your model and custom model admin class.
Name and other data#
Sometimes you need more functionality, such as extra metadata and custom functions. The Category
model in this package does this.
Create a model that subclasses
CategoryBase
as above.Add new fields to the model. The
Category
model adds these extra fields.1from categories import models, settings 2from categories.base import CategoryBase 3 4 5class Category(CategoryBase): 6 thumbnail = models.FileField( 7 upload_to=settings.THUMBNAIL_UPLOAD_PATH, 8 null=True, 9 blank=True, 10 storage=settings.THUMBNAIL_STORAGE, 11 ) 12 thumbnail_width = models.IntegerField(blank=True, null=True) 13 thumbnail_height = models.IntegerField(blank=True, null=True) 14 order = models.IntegerField(default=0) 15 alternate_title = models.CharField( 16 blank=True, default="", max_length=100, help_text="An alternative title to use on pages with this category." 17 ) 18 alternate_url = models.CharField( 19 blank=True, 20 max_length=200, 21 help_text="An alternative URL to use instead of the one derived from " "the category hierarchy.", 22 ) 23 description = models.TextField(blank=True, null=True) 24 meta_keywords = models.CharField( 25 blank=True, default="", max_length=255, help_text="Comma-separated keywords for search engines." 26 ) 27 meta_extra = models.TextField( 28 blank=True, default="", help_text="(Advanced) Any additional HTML to be placed verbatim " "in the <head>" 29 )
Add new methods to the model. For example, the
Category
model adds several new methods, including overriding thesave()
method.1from categories.models import Category 2 3 4def save(self, *args, **kwargs): 5 if self.thumbnail: 6 import django 7 from django.core.files.images import get_image_dimensions 8 9 if django.VERSION[1] < 2: 10 width, height = get_image_dimensions(self.thumbnail.file) 11 else: 12 width, height = get_image_dimensions(self.thumbnail.file, close=True) 13 else: 14 width, height = None, None 15 16 self.thumbnail_width = width 17 self.thumbnail_height = height 18 19 super(Category, self).save(*args, **kwargs)
Alter
Meta
orMPTTMeta
class. Either of these inner classes can be overridden, however yourMeta
class should inheritCategoryBase.Meta
. Options forMeta
are in the Django-MPTT docs.1from categories.base import CategoryBase 2 3 4class Meta(CategoryBase.Meta): 5 verbose_name_plural = "categories" 6 7 8class MPTTMeta: 9 order_insertion_by = ("order", "name")
For the admin, you must create a form that subclasses
CategoryBaseAdminForm
and at least sets theMeta.model
attribute. You can also alter the form fields and cleaning methods, asCategory
does.1from categories.base import CategoryBaseAdminForm 2from categories.models import Category 3 4 5class CategoryAdminForm(CategoryBaseAdminForm): 6 class Meta: 7 model = Category 8 9 def clean_alternate_title(self): 10 if self.instance is None or not self.cleaned_data["alternate_title"]: 11 return self.cleaned_data["name"] 12 else: 13 return self.cleaned_data["alternate_title"]
Next you must subclass
CategoryBaseAdmin
and assign theform
attribute the form class created above. You can alter any other attributes as necessary.1from categories.admin import CategoryAdminForm 2from categories.base import CategoryBaseAdmin 3 4 5class CategoryAdmin(CategoryBaseAdmin): 6 form = CategoryAdminForm 7 list_display = ("name", "alternate_title", "active") 8 fieldsets = ( 9 (None, {"fields": ("parent", "name", "thumbnail", "active")}), 10 ( 11 "Meta Data", 12 { 13 "fields": ("alternate_title", "alternate_url", "description", "meta_keywords", "meta_extra"), 14 "classes": ("collapse",), 15 }, 16 ), 17 ( 18 "Advanced", 19 { 20 "fields": ("order", "slug"), 21 "classes": ("collapse",), 22 }, 23 ), 24 )