Creating a CMS Website with Django

How to build a CMS website with Django.


As a newcomer to Django and Django-cms I had a tough time, as all newcomers do, getting my head around how to get things working.  So what i did was I built a crib sheet as I went along of all the steps I undertook to get things up and running.  This is written using the assumption that the website is being installed on Django 1.8.6 but I'm sure the basic steps can easily be modified for different versions of Django as well as different flavours of linux.

The following code is offered without any warranties or guaranties and is published here to hopefully help other newbies on their travels.

Happy coding! 


Building a CMS Website in Django 


If you are creating a new application, go to where you are wanting to house your application ie /var/www and create a new directory for your new application. mkdir <application name> 

 Then cd to that directory  cd <application name> 

 Assuming you already have virtualenvwrapper installed on your system, then you can simply do the following.  Otherwise you need to install Virtualenvwrapper first. 

 Create a virtual environment within your new application.  This allows you to install different applications and versions required for your application whilst keeping them separate from other applications you may be running. virtualenv env (I call it env but you can call it anything you like.) 

 Then activate you environment. source <path>/<application name>/<env>/bin/activate  

 This should give you the following styled user prompt. (env) <user>@<server>:<currentpath>$ 

 Next install the pillow dependency with the following command: pip install pillow 

 If you are using postgresql install the database software required or the one applicable to your chosen backend. pip install psycopg2 

Now we need to install Django inside our virtual environment.  At this stage we are not installing the latest version due to compatibility issues that I was having. So we are going to force an install of version 1.8.6 as follows.  Installing without the ==1.8.6 will automatically install the latest version. pip install Django==1.8.6 

Install Django cms by running the following command pip install django-cms 

Next create your project using the Django admin function django-admin startproject <project name> . (Note the space and period after the <project name> this is so we don’t create a further unnecessary level in our structure.) 

As a rule I am going to name the project the same as the containing folder where the project lives as previously created. 

Open your project file and add the following to the top of the file after import OS.

Import django gettext = lambda s: s
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
SITE_ROOT = os.path.dirname(os.path.realpath(__file__))

Don’t forget to set your ALLOWED_HOSTS tags for apache. ALLOWED_HOSTS = [ ‘’, ‘’, etc ] 

Make sure you settings file has a SITE_ID label. This is a numeric value which corresponds to the site primary key held in the database.  Normally I would default this to 1 for new installations but you can set it to 2 if an example website installed automatically.  Basically you can use this setting to allow you to run multiple websites from within the same database. 

SITE_ID = 1 

Now add the following applications to the INSTALLED APPS section of your file.  You should already have all the admin and auth ones there already.


Add the following classes to the Middleware Section. Make sure you also include django.middleware.locale.LocaleMiddleware after the SessionMiddleware entry


Then in the context_processors section of TEMPLATES in your file add the following at the end of any processors you may already have listed.


 Add at least one template to CMS_TEMPLATES; for example:

        ('template_1.html', 'Template One'),   
        ('template_2.html', 'Template Two'),

Now set up your database connection as follows. Using Postgresql as an example.

           ‘default’: {
                     ‘ENGINE’: ‘django.db.backends.postgresql_psycopg2’, 
                     ‘NAME’: ‘<database name>’,
                     ‘USER’: ‘_system’,
                     ‘PASSWORD’: ‘0bv10us’,
                     ‘HOST’: ‘’,
                     ‘PORT’: ‘<database port number>’,

Add at least one language to Languages though you can add whatever languages you want. for example: Make sure the code matches the tag that may already be set in

LANGUAGE_CODE. LANGUAGES = [ ('en-us', 'English'), ] 

Lastly in the file make sure you have your static paths defined properly.  They should look like this.

MEDIA_ROOT = os.path.join(SITE_ROOT, “media”) MEDIA_URL = “/media/” 

STATIC_ROOT = os.path.join(SITE_ROOT, “static”) STATIC_URL = ‘/static/’ 



Now open and modify the project file to basically look like this.

from django.conf.urls import include, url
from django.contrib import admin
from django.conf.urls.i18n import i18n_patterns
from django.conf import settings 


urlpatterns = i18n_patterns(
         url(r’^admin/’, include(,
         url(r’^’, include(‘cms.urls’)),

The django CMS handles media files (CSS stylesheets and JavaScript files) required by CMS plugins using django-sekizai. This requires you to define at least two sekizai namespaces in your templates: js and css. You can do so using the render_block template tag from the sekizai_tags template tag library. We highly recommended putting the {% render_block "css" %} tag as the last thing before the closing </head> HTML tag and the {% render_block "js" %} tag as the last thing before the closing </body> HTML tag in your html templates. 

Now edit your file and make it look like this.

import os import sys 

from django.core.wsgi import get_wsgi_application 

path = ‘<path to your application>/<application name>’

if path not in sys.path:

os.environ.setdefault(“DJANGO_SETTINGS_MODULE”, “<project name>.settings”) 

application = get_wsgi_application() 

Make sure you have created your templates directory and in the first level create a base.html file as well as at least one template at the same level which extends the base.html file. 

Base.html should look like this as a starting point.

{% load cms_tags sekizai_tags %}

                   {% render_block “css” %}

                   {% cms_toolbar %}
                   {% placeholder base_content %}
                   {% block base_content %}{% endblock %}
                   {% render_block “js” %}

and the template_1.html should look like this as a starting point.

{% extends “base.html” %}

{% load cms_tags %} 

{% block base_content %}
         {% placeholder template_1_content %}
{% endblock %} 

Be sure to have 'django.contrib.sites' in INSTALLED_APPS and set SITE_ID parameter in your settings: they may be missing from the settings file generated by django-admin depending on your Django version and project template. 

Now switch back to your project root directory and synchronise everything with your database backend by running the following command. If syncdb is not recognised as a valid command, you are probably running a later version of Django as this command was deprecated in version 1.9.  To fix this run python migrate and create a superuser manually using python createsuperuser  

python syncdb  

Now run a check to make sure that everything is ok in your setup. python cms check 

At this point you should be able to log in to the admin portion of your website using the superuser details you created previously.  If you go into the pages in the admin section, the rendering may not look right.  This is because the cms static files are not being found as they are buried in your virtual environment and we’ll dig them out later.  

Phase 2 Install various recommended plugins to improve functionality.   

pip install djangocms_text_ckeditor
pip install djangocms-column
pip install djangocms-style
pip install djangocms-link 

Add these apps to the already modified INSTALLED_APPS section of the file (Note the underscores as opposed to hyphens in the last section.


Now run a migrate to synchronise these plugins with the database.  Note that sometimes you may see the migration killed.  This is usually caused by low resources such as if you are running on an entry level VPS server. 

python migrate 

Phase 3 Install the Django-filer module by running these installations.

pip install django-filer 

Add these apps to the already modified INSTALLED_APPS section of the file.


Now run a migrate to synchronise these plugins with the database

python migrate 

Next install the cmsplugin to work with Django-filer which you’ve just installed.

pip install cmsplugin-filer 

Add these apps to the already modified INSTALLED_APPS section of the


Django messages framework is now required for the toolbar to work properly. To enable it you must check that the following settings are set: INSTALLED_APPS: must contain 'django.contrib.messages' MIDDLEWARE_CLASSES: must contain 'django.contrib.messages.middleware.MessageMiddleware' TEMPLATES["OPTIONS"]["context_processors"]: must contain 'django.contrib.messages.context_processors.messages'  

Now run a migrate to synchronise these plugins with the database

python migrate 

Next install various dependencies.

pip install djangocms-googlemap
pip install djangocms-inherit
pip install djangocms-snippet 

If you want to have versioning for your content, also install Django-reversion with the following command

pip install django-reversion 

Add the following to INSTALLED_APPS in your file.

‘reversion’, (if you installed the Django-reversion app mentioned above) 

For easy_thumbnails to support retina displays (recent MacBooks, iOS) add to


It is possible to define the important part of an image (the subject location) in the admin interface for django-filer images. This is very useful when later resizing and cropping images with easy_thumbnails. The image can then be cropped automatically in a way, that the important part of the image is always visible. To enable automatic subject location aware cropping of images replace easy_thumbnails.processors.scale_and_crop with filer.thumbnail_processors.scale_and_crop_with_subject_location in the THUMBNAIL_PROCESSORS setting:


Note when building web pages: - To crop an image and respect the subject location: {% load thumbnail %} {% thumbnail obj.img 200x300 crop upscale subject_location=obj.img.subject_location %} 

Now add in the CMS Middleware classes as follows paying particular attention to the order in which they are placed.


   'cms.middleware.utils.ApphookReloadMiddleware', (place this as close to the top as possible’)

Now run a migrate to synchronise these plugins with the database

python migrate 

If you want to use the Grid and Table plugins you need to install them using the following:

pip install djangocms-grid
pip install djangocms-table 

Then you need to add them to the INSTALLED APPS section of you file.


The djangocms_table plugin contains south migrations which we no longer use in Django 1.8 onwards.  Therefore you need to go to the djangocms_table folder which is stored in your virtual environment.  If you have packaged your environment with the project, the path you need is as follows:

cd <path to project>/<project name>/<virtual env>/lib/python<version>/sitepackages/djangocms_table 

I suggest you rename the migrations folder to south_migrations and throw away the .pyc files in there. Then create a new migrations folder at the same level as the newly renamed south_migrations.  Inside create two files and 

Next you need to edit the file and make it look like this:

from __future__ import unicode_literals
from django.db import models, migrations 

class Migration(migrations.Migration): 
    dependencies = [('cms', '__first__'),] 
    operations = [migrations.CreateModel(
                 ('cmsplugin_ptr', models.OneToOneField(parent_link=True, auto_created=True, primary_key=True, serialize=False, to='cms.CMSPlugin')),
                 ('name', models.CharField(max_length=256, verbose_name='name')),
                 ('headers_top', models.PositiveSmallIntegerField(default=1, verbose_name='top')),
                 ('headers_left', models.PositiveSmallIntegerField(default=0, verbose_name='left')),
                 ('headers_bottom', models.PositiveSmallIntegerField(default=0, verbose_name='bottom')),
                 ('table_data', models.TextField(verbose_name='table data')),
                 'abstract': False,

Now run a migrate to synchronise these plugins with the database

python migrate 

Hopefully...that should be it and you should be able to get up and running now with your new CMS website.