Django Categories 1.5.3 documentation

This Page

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.

  1. Create a model that subclasses CategoryBase

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    from categories.models import CategoryBase
    
    
    class SimpleCategory(CategoryBase):
        """
        A simple of catgorizing example
        """
    
        class Meta:
            verbose_name_plural = 'simple categories'
    
  2. Create a subclass of CategoryBaseAdmin.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    from django.contrib import admin
    
    from categories.admin import CategoryBaseAdmin
    
    from .models import SimpleCategory
    
    
    class SimpleCategoryAdmin(CategoryBaseAdmin):
        pass
    
    
    admin.site.register(SimpleCategory, SimpleCategoryAdmin)
    
  3. 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.

  1. Create a model that subclasses CategoryBase as above.

  2. Add new fields to the model. The Category model adds these extra fields.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    from categories import models, settings
    from categories.base import CategoryBase
    
    
    class Category(CategoryBase):
        thumbnail = models.FileField(
            upload_to=settings.THUMBNAIL_UPLOAD_PATH,
            null=True, blank=True,
            storage=settings.THUMBNAIL_STORAGE,)
        thumbnail_width = models.IntegerField(blank=True, null=True)
        thumbnail_height = models.IntegerField(blank=True, null=True)
        order = models.IntegerField(default=0)
        alternate_title = models.CharField(
            blank=True,
            default="",
            max_length=100,
            help_text="An alternative title to use on pages with this category.")
        alternate_url = models.CharField(
            blank=True,
            max_length=200,
            help_text="An alternative URL to use instead of the one derived from "
                      "the category hierarchy.")
        description = models.TextField(blank=True, null=True)
        meta_keywords = models.CharField(
            blank=True,
            default="",
            max_length=255,
            help_text="Comma-separated keywords for search engines.")
        meta_extra = models.TextField(
            blank=True,
            default="",
            help_text="(Advanced) Any additional HTML to be placed verbatim "
                      "in the <head>")
    
  3. Add new methods to the model. For example, the Category model adds several new methods, including overriding the save() method.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    from categories.models import Category
    
    
    def save(self, *args, **kwargs):
        if self.thumbnail:
            from django.core.files.images import get_image_dimensions
            import django
            if django.VERSION[1] < 2:
                width, height = get_image_dimensions(self.thumbnail.file)
            else:
                width, height = get_image_dimensions(self.thumbnail.file, close=True)
        else:
            width, height = None, None
    
        self.thumbnail_width = width
        self.thumbnail_height = height
    
        super(Category, self).save(*args, **kwargs)
    
  4. Alter Meta or MPTTMeta class. Either of these inner classes can be overridden, however your Meta class should inherit CategoryBase.Meta. Options for Meta are in the Django-MPTT docs.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    from categories.base import CategoryBase
    
    
    class Meta(CategoryBase.Meta):
        verbose_name_plural = 'categories'
    
    
    class MPTTMeta:
        order_insertion_by = ('order', 'name')
    
  5. For the admin, you must create a form that subclasses CategoryBaseAdminForm and at least sets the Meta.model attribute. You can also alter the form fields and cleaning methods, as Category does.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    from categories.base import CategoryBaseAdminForm
    from categories.models import Category
    
    
    class CategoryAdminForm(CategoryBaseAdminForm):
        class Meta:
            model = Category
    
        def clean_alternate_title(self):
            if self.instance is None or not self.cleaned_data['alternate_title']:
                return self.cleaned_data['name']
            else:
                return self.cleaned_data['alternate_title']
    
  6. Next you must subclass CategoryBaseAdmin and assign the form attribute the form class created above. You can alter any other attributes as necessary.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    from categories.admin import CategoryAdminForm
    from categories.base import CategoryBaseAdmin
    
    
    class CategoryAdmin(CategoryBaseAdmin):
        form = CategoryAdminForm
        list_display = ('name', 'alternate_title', 'active')
        fieldsets = (
            (None, {
                'fields': ('parent', 'name', 'thumbnail', 'active')
            }),
            ('Meta Data', {
                'fields': ('alternate_title', 'alternate_url', 'description',
                           'meta_keywords', 'meta_extra'),
                'classes': ('collapse',),
            }),
            ('Advanced', {
                'fields': ('order', 'slug'),
                'classes': ('collapse',),
            }),
        )