Django with Django-CMS

I recently found myself starting to design a flexible model for the different pages of my Django website.  After an enjoyable morning thinking through how to structure the data it hit me: I was designing a content management system! Surely someone has done that before… So I turned my attention to Django-CMS.

To get a basic Django-CMS project running there is an impressive list of changes you need to make to your new project’s settings, but if you follow the tutorial it all works well, and you can get a page template of your own design up and running so that someone else can add content to it through Django’s very nice admin console.  Note – make sure you follow the tutorial for the same version of Django-CMS as you have installed!  Somehow I wound up following an older tutorial and it has caused me a lot of pain – lots of settings were subtly different.

Adding the tables

I found myself going around in circles trying to get South to put the Django-CMS tables into my pre-existing project, until I found this stackoverflow post.  The accepted answer is commenting out south from the INSTALLED_APPS, then running the usual python syncdb command, then uncommenting it and then doing a fake migration ( migrate --fake).  Stuff like this makes me wonder if I’m really making my life any easier using Django… perhaps I should chuck it in and use one of the more popular frameworks? (But then I also remember how hard it was to move this blog off the front page of my WordPress site…)

Adding your own css and js

I see that Django-CMS uses some other packages, including django-sekizai to render css and javascript. I want to put my own css file in of course, and use Twitter Bootstrap too. From the django-sekizai documentation, you just need to add:

{% addtoblock "css" %}
	<link href="/media/css/stylesheet.css" rel="stylesheet" media="screen" type="text/css">
{% endaddtoblock %}

along with something similar for js.

However, there is a trick here, elucidated in this stackoverflow post.  These static files that you add must go into a differently named folder like local-static in your app directory, and you must add this to your

    # Put strings here, like /home/html/static or C:/www/django/static.
    # Always use forward slashes, even on Windows.
    # Don't forget to use absolute paths, not relative paths.
    os.path.join(PROJECT_PATH, "local-static"),

Talk about a trap for young players!

Outstanding – why is the static file directory inside the app directory after doing this, when the PROJECT_PATH appears to be one level up?

How to integrate an existing app into Django-CMS

This has been a very painful process, and I have yet to complete it. I am using the “AppHook” approach, though the documentation lists this as third out of five methods with little guidance to help you choose.

I made the following changes to my RTloginapp (which is described in this post):

Add a new file RTloginapp/

from cms.app_base import CMSApp
from cms.apphook_pool import apphook_pool
from django.utils.translation import ugettext_lazy as _

class RTLoginApphook(CMSApp):
    name = _("RTLoginApphook")
    urls = ["RTloginapp.urls"]


Add a new file RTloginapp/

from django.conf.urls.defaults import patterns, include, url
import django.contrib.auth.views

urlpatterns = patterns('RTloginapp.views',

    url(r'^/?$', 'signin', name="signin"),
    url(r'^login/?$', 'signin'),
    url(r'^join/?$', 'join', {"forgot_link":"//password/reset", "activate_link":"//register"}),
    url(r'^register/?$', 'activate'),
    url(r'^signout/?$', 'signout'),

    url(r'^password/reset/?$', django.contrib.auth.views.password_reset,
        {'post_reset_redirect' : '//password/reset/done/'}),
    url(r'^password/reset/done/?$', django.contrib.auth.views.password_reset_done),
    url(r'^password/reset/(?P<uidb36>[0-9A-Za-z]+)-(?P<token>.+)/?$', django.contrib.auth.views.password_reset_confirm,
        {'post_reset_redirect' : '//password/done/'}),
    url(r'^password/done/?$', django.contrib.auth.views.password_reset_complete),

And then go into the admin panel and add an “accounts” page with the application (under advanced settings) set to RTLoginApphook.

Note if you muck up the urls reference, I found I needed to uninstall the apphook using:

python cms uninstall apphooks RTLoginApphook

and then go back to the admin page and hook it back up again to a page.

Note the RTloginapp templates may need to be modified if you have renamed any of the blocks, e.g. the Django-CMS tutorial uses “base_content” as the block name, where I wrote login/login.html to use “content”.

What are menus?

It took me a while to find a description of what was meant by a menu.  I think this Django-CMS documentation page gives a good enough introduction.

My “en” pages are missing!

This turned out to be due to the order of the MIDDLEWARE_CLASSES (a relic of the fact that I had originally followed an older tutorial and fixed it manually by adding cms.middleware.multilingual.MultilingualURLMiddleware to the end… it should be before the other cms.middleware classes). Not an easy error to find.


I wavered several times on whether to use Django-CMS.  It felt like many of the concepts were too heavy (what are app hooks?), there was limited documentation, and googling only sometimes solved my problems.  But in the end, I was able to push through and start using it, and I have found it very powerful.


3 thoughts on “Django with Django-CMS”

  1. Excellent tutorial Arthur. Would you be interested in trying a new Django CMS called Butter ( designed to let you spin up a new Django-powered blog in 5 minutes? We’d love to have you try it out and get your thoughts on how it compares to Django CMS.

  2. First of THANK YOU!
    i was also doing the tutorial coz i needed a cms. Though the tutorial was easy i was stock on how to apply own css.

    A few questions if you don’t mind.
    1. How come the templates folder is located at myproject/ along with the Why not on myproject/myproject/ where the and other files are located ?
    2. Where did you put your static folder? Is it inside myproject/myproject along with the

    Appreciate your response

    1. Hi Eric, you’re welcome – good questions. I don’t use the template folder in myproject/ – I deleted it, and put one in myproject/myproject instead. The template loaders can find it in either place, so I think that’s a matter of personal taste.
      I did the same for my static folder. I now use:

      if MY_ENV=="dev": # i.e. for development only
      STATIC_ROOT = os.path.join(PROJECT_PATH, "collectedstatic")


      STATICFILES_DIRS = ( os.path.join(PROJECT_PATH, 'static'), )

      That way I can keep using directories named ‘static’ as before, and the directory they are collected to has the different name. In production, they are collected somewhere different (e.g. on webfaction, to a specialist static webapp).

      Hope that helps!

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>