I’ve been trying to get to grips with Heroku lately. Here’s how to install django-cms.

At FARM, we heavily use django-cms, but our traditional methods for deployment and hosting aren’t necessarily compatible with the principles of the 12-factor application. In particular, I wanted to explore the issues around file/upload handling (and persistence) and working with databases. So, here are the steps which I took.

At the time of writing, django-cms 3.0 is right around the corner, but I am more familiar with the 2.4 branch. I’ll update this post when 3.0 is available, if enough people contact me.

Prerequisites

In this article, all the local commands are run on an OSX machine, but as long as you have a working python, virtualenv and pip, the steps should be the same regardless of the platform. I used Postgres.app for my local database.

There are some basic things to setup before starting.

First, setup the application in Heroku:

Clone the repository, and make an initial commit:

$ git clone git@heroku.com:farm-django-cms-test.git 
Cloning into 'farm-django-cms-test'...
Initializing repository, done.
warning: You appear to have cloned an empty repository.
$ cd farm-django-cms-test
$ echo "farm-django-cms-test" >> README
$ git add README
$ git commit -m "Initial commit of a README file"

This is optional, but I wouldn’t be comfortable having just one remote, so add a new remote, and push there. We use BitBucket.

$ git remote add bitbucket git@bitbucket.org:wearefarm/farm-django-cms-test.git
$ git push -u bitbucket --all
Counting objects: 3, done.
Writing objects: 100% (3/3), 234 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@bitbucket.org:wearefarm/farm-django-cms-test.git
 * [new branch]      master -> master
Branch master set up to track remote branch master from bitbucket.

At this stage, setup a .gitignore, add and then commit it. Mine looks like this:

venv
*.pyc
static

Dependencies

We need to install a virtualenv, and install Django, django-cms, and a couple of other packages which we will need later on.

$ virtualenv --no-site-packages venv
New python executable in env/bin/python
Installing setuptools, pip...done.
$ source venv/bin/activate
(venv)$ pip install Django==1.5.5 psycopg2 gunicorn dj-database-url django-cms==2.4.3 pillow django-storages
<...>
Successfully installed Django psycopg2 gunicorn dj-database-url django-cms Pillow django-storages django-classy-tags south html5lib django-mptt django-sekizai six
Cleaning up...

Now we have everything we will need, freeze those requirements:

(venv)$ pip freeze > requirements.txt

Django on Heroku

I wanted to make sure that I had everything in place to run Django on Heroku at this point. So, create a Django project:

(venv)$ django-admin.py startproject example .

Then, setup a Procfile and test it with foreman:

(venv)$ echo "web: gunicorn example.wsgi" > Procfile
(venv)$ foreman start
20:50:20 web.1  | started with pid 3566
20:50:20 web.1  | 2014-03-22 20:50:20 [3566] [INFO] Starting gunicorn 18.0
20:50:20 web.1  | 2014-03-22 20:50:20 [3566] [INFO] Listening at: http://0.0.0.0:5000 (3566)
20:50:20 web.1  | 2014-03-22 20:50:20 [3566] [INFO] Using worker: sync
20:50:20 web.1  | 2014-03-22 20:50:20 [3569] [INFO] Booting worker with pid: 3569

I could then test if Django was running locally, by visiting http://0.0.0.0:5000:

Let’s push this code to Heroku, and make sure we get the same results.

(venv)$ git add .
(venv)$ git commit -m "Initial Django code."
[master 7550808] Initial Django code.
 6 files changed, 133 insertions(+)
 create mode 100644 Procfile
 create mode 100644 example/__init__.py
 create mode 100644 example/settings.py
 create mode 100644 example/urls.py
 create mode 100644 example/wsgi.py
 create mode 100755 manage.py
 create mode 100644 requirements.txt
(venv)$ git push origin master
Initializing repository, done.
Counting objects: 16, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (11/11), done.
Writing objects: 100% (16/16), 2.72 KiB, done.
Total 16 (delta 0), reused 0 (delta 0)

-----> Python app detected
-----> No runtime.txt provided; assuming python-2.7.6.
-----> Preparing Python runtime (python-2.7.6)
-----> Installing Setuptools (2.1)
-----> Installing Pip (1.5.4)
-----> Installing dependencies using Pip (1.5.4)

<...>

       Successfully installed Django Pillow South dj-database-url django-classy-tags django-cms django-mptt django-sekizai django-storages gunicorn html5lib psycopg2 six
       Cleaning up...

-----> Discovering process types
       Procfile declares types -> web

-----> Compressing... done, 38.2MB
-----> Launching... done, v5
       http://farm-django-cms-test.herokuapp.com/ deployed to Heroku

To git@heroku.com:farm-django-cms-test.git
 * [new branch]      master -> master

You’ll notice the URL of the deployed application above (though I assume that your URL will be slightly different). At the moment, if you visit that URL, then you won’t get a response. We need to add a dyno:

(venv)$ heroku ps:scale web=1
Scaling dynos... done, now running web at 1:1X.

Now, visit the URL:

Now that we have our Django project running on Heroku, all that remains in part two is to complete the django-cms setup, and then deal with our static media and uploads.