Extending Entry model

New in version 0.8.

The Entry model bundled in Zinnia can now be extended and customized.

This feature is useful for who wants to add some fields in the model, or change its behavior. It also allows Zinnia to be a really generic and reusable application.

Why extending ?

Imagine that I find Zinnia really great for my project but some fields or features are missing to be the Weblog app that suits to my project. For example I need to add a custom field linking to an image gallery, two solutions:

  • I search for another Django blogging app fitting my needs.
  • I do a monkey patch, into the Zinnia code base.

These two solutions are really bad.

For the first solution maybe you will not find the desired application and also mean that Zinnia is not a reusable application following the Django’s convention. For the second solution, I don’t think that I need to provide more explanations about the evil side of monkey patching (evolution, reproduction...). That’s why Zinnia provides a third generic solution.

  • Customizing the Entry model noninvasively with the power of class inheritance !

The extension process is done in three main steps:

  1. Write a class containing your customizations.
  2. Register your class into Zinnia to be used.
  3. Update the EntryAdmin class accordingly.

In the suite of this document we will show how to add an image gallery into the Entry model to illustrate the concepts involved. We assume that the pieces of codes written for this document belong in the zinnia_gallery package/application.

Writing model extension

The first step to extend the Entry model is to define a new class inherited from the EntryAbstractClass and add your fields or/and override the inherited methods if needed. So in zinnia_gallery let’s write our new class in a file named entry_gallery.py.

from django.db import models
from zinnia_gallery.models import Gallery
from zinnia.models.entry import EntryAbstractClass

class EntryGallery(EntryAbstractClass):
    gallery = models.ForeignKey(Gallery)

    def __unicode__(self):
        return u'EntryGallery %s' % self.title

    class Meta(EntryAbstractClass.Meta):
        abstract = True

In this code sample, we add a new ForeignKey field named gallery pointing to a Gallery model defined in zinnia_gallery.models and we override the EntryAbstractClass.__unicode__() method.


You have to respect 3 important rules to make extending working :

  1. Do not import the Entry model in your file defining the extended model because it will cause a circular importation.
  2. Do not put your abstract model in a file named models.py, it will not work for a non obvious reason.
  3. Don’t forget to tell that your model is abstract. Otherwise a table will be created and the extending process will not work as expected.

See also

Model inheritance for more information about the concepts behind the model inheritence in Django and the limitations.

Considerations about the database

If you do the extension of the Entry model after the syncdb command, you have to manually alter the Zinnia’s tables for reflecting your changes made on the model class. In the case where your database is empty, you can simply execute the reset command on the Zinnia application for destroying the old database schema and installing the new one.

Now if you are using South and try to write a new migration for reflecting your changes, the migration script will be written in the zinnia.migrations module, which is not recommended because the result is not replicable for multiple installations and breaks the migration system with future releases of Zinnia.

Fortunatly South provides an elegant solution with the SOUTH_MIGRATION_MODULES setting. Once this setting done for the 'zinnia' key, because you are now out the Zinnia’s default migrations flow, you have to delete the ghost migrations for Zinnia. At this step you can now start to write new migrations.

It’s recommended that the new initial migration represents the default Entry schema provided by Zinnia, because after that, you just have to write a new migration for reflecting your changes, and you can alter your database schema with the migrate command.

Registering the extension

Once your extension class is defined you simply have to register it, with the ZINNIA_ENTRY_BASE_MODEL setting in your Django settings. The expected value is a string representing the full Python path to the extented model’s class name. This is the easiest part of the process.

Following our example we must add this line in the project’s settings.

ZINNIA_ENTRY_BASE_MODEL = 'zinnia_gallery.entry_gallery.EntryGallery'

If an error occurs when your new class is imported a warning will be raised and the EntryAbstractClass will be used.

Updating the admin interface

Now we should update the Entry‘s admin class to reflect our changes and use the new fields.

To do that we will write a new admin class inherited from EntryAdmin and use the admin site register/unregister mechanism for using our new class.

In the file zinnia_gallery/admin.py we can write these code lines for adding the gallery field:

from django.contrib import admin
from django.utils.translation import ugettext_lazy as _

from zinnia.models.entry import Entry
from zinnia.admin.entry import EntryAdmin

class EntryGalleryAdmin(EntryAdmin):
  # In our case we put the gallery field
  # into the 'Content' fieldset
  fieldsets = ((_('Content'), {'fields': (
    'title', 'content', 'image', 'status', 'gallery')}),) + \

# Unregister the default EntryAdmin
# then register the EntryGalleryAdmin class
admin.site.register(Entry, EntryGalleryAdmin)

Note that the zinnia_gallery application must be registered in the INSTALLED_APPS setting after the zinnia application for applying the register/unregister mechanism in the admin site.

Now we can easily customize the templates provided by Zinnia to display the gallery field into the Weblog’s pages.

For more information you can see another implementation example in the cmsplugin-zinnia package.