django CMS Page and Title extension

Page is a Page is a Page is a Page

The other day, while discussing designs with a client, he came up with the requirement of having author information on each page of his website. It was a good idea, but how could we implement that? Using a dedicated plugin in each page would be feasible but definitely cumbersome. To handle such cases a common pattern in the CMS world is to have a very broad definition of what a page is. A Page object is often just a base to create more complex objects (commonly named 'Content type' or 'Classes') by adding attributes and properties, while still remaining a Page object managed by the CMS. In this case we could create an 'AuthorPage' (or whatever) with a link to an Author object. django CMS took a very different approach and stayed true to this choice ever since. Page class is unique, and you're not supposed to mess with it.

The django CMS way

django CMS is a good Django citizen in the first place and tries to do a great job at one thing i.e. being a CMS and managing unstructured content, while leaving tasks such as taking care of structured content, user interaction and so on to specialized Django applications. In other words, if you want a list of news, don't try to organize pages to emulate a list of news: write a couple dozen lines of Python, and you'll end up with a far better news application than a bunch of pages could ever be!

Extending the CMS Page

Nevertheless sometimes the need to add some information to the Page model arise, without really making it other than a Page, classification tags, authorship information, or extended meta tags, just some examples of information that may be needed to be attached to any page. Up until now there wasn't any cleaner way to achieve this, than writing a bunch of hackish code. Since 3.0 this has changed for the better. The Page Extensions API permits adding attributes to Page and Title objects, augmenting the storable information for each that can be later retrieved in the template or everywhere in your Django project. The good thing is, everything is totally transparent and django-ish: PageExtension and TitleExtension (the base classes you're going to use) are just models with a OneToOneField to Page or Title models, and most of the work the API code does is, keeping the state sane when you populate those models or publish pages. Accessing a PageAuthor instance, for example in the template is something like request.current_page.pageauthor.author with no real magic behind the curtains (if you except the Django ORM magic!)

Implementing an extension

Extension are recommended to live in a separate application, especially if they have relations with other models. To implement a Page / Title extension you must create three classes:

the extension model: it's where the extra information are going to be stored;

the extension admin: it's the ModelAdmin for the model;

the extension toolbar items: the extension admin is not “usable” from the main admin dashboard and you must tie it to the toolbar for it to work properly.

Extension model - PageAuthorProperties

The extension model is a model extending from a defined parent that handles the publishing process and other internal working; it must be defined in models.py. In this way, the resulting model is quite simple and straightforward:

Toolbar - PageAuthorToolbar

Toolbar is the way django CMS allows you to customise your editing interface.

Implementing a toolbar is a bit a low level thing as you are required to check for the permissions and add the proper toolbar item in the desired position. Toolbar must by defined in cms_toolbar.py file.