Although I’m a Ruby on Rails lover today I’m going to write about how to deploy a fresh installation of django-CMS to Heroku using Amazon S3 for storing static files.
This is a compilation from these sites:
First of all we’ll create our application directory my_app
$ mkdir my_app && cd my_app
Next, we’ll create our Python’s virtual environment using virtualenv
and activate it
$ virtualenv --no-site-packages venv
$ source venv/bin/activate
Now we can install required Python packages like django itself, django-cms, gunicorn (web server) and some others with pip
$ pip install Django psycopg2 gunicorn dj-database-url django-cms PIL django-storage
We’ll need the requirements.txt
file to deploy to Heroku
$ pip freeze > requirements.txt
And create our django project inside the current directory:
$ django-admin.py startproject my_app .
Add these lines to the my_app/settings.py
file
# -*- coding: utf-8 -*-
import os
gettext = lambda s: s
PROJECT_PATH = os.path.abspath(os.path.dirname(__file__))
and add these in your INSTALLED_APPS
array inside my_app/settings.py
INSTALLED_APPS = (
# ...
'cms',
'mptt',
'menus',
'south',
'sekizai',
'cms.plugins.file',
'cms.plugins.flash',
'cms.plugins.googlemap',
'cms.plugins.link',
'cms.plugins.picture',
'cms.plugins.snippet',
'cms.plugins.teaser',
'cms.plugins.text',
'cms.plugins.video',
'cms.plugins.twitter',
'storages',
)
And add these to your MIDDLEWARE_CLASSES
and TEMPLATE_CONTEXT_PROCESSORS
arrays inside my_app/settings.py
MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.doc.XViewMiddleware',
'django.middleware.common.CommonMiddleware',
'cms.middleware.page.CurrentPageMiddleware',
'cms.middleware.user.CurrentUserMiddleware',
'cms.middleware.toolbar.ToolbarMiddleware',
'cms.middleware.language.LanguageCookieMiddleware',
)
TEMPLATE_CONTEXT_PROCESSORS = (
'django.contrib.auth.context_processors.auth',
'django.core.context_processors.i18n',
'django.core.context_processors.request',
'django.core.context_processors.media',
'django.core.context_processors.static',
'cms.context_processors.media',
'sekizai.context_processors.sekizai',
)
Now we’ll configure our templates. First, create the directory where we’ll put our django templates
$ mkdir templates
and create two empty files:
$ touch templates/template_1.html
$ touch templates/template_2.html
in order two access these templates we have to put them in our settings.py
file and set up available languages
TEMPLATE_DIRS = (
# The docs say it should be absolute path: PROJECT_PATH is precisely one.
# Life is wonderful!
os.path.join(PROJECT_PATH, "templates"),
)
CMS_TEMPLATES = (
('template_1.html', 'Template One'),
('template_2.html', 'Template Two'),
)
LANGUAGES = [
('en', 'English'),
]
Now let’s configure our my_app/urls.py
. First, uncomment this line
admin.autodiscover()
And add these lines
urlpatterns = i18n_patterns('',
url(r'^admin/', include(admin.site.urls)),
url(r'^', include('cms.urls')),
)
if settings.DEBUG:
urlpatterns = patterns('',
url(r'^media/(?P<path>.*)$', 'django.views.static.serve',
{'document_root': settings.MEDIA_ROOT, 'show_indexes': True}),
url(r'', include('django.contrib.staticfiles.urls')),
) + urlpatterns
Now let’s create the base layout inside templates directory templates/base.html
{% load cms_tags sekizai_tags %}
<html>
<head>
{% render_block "css" %}
</head>
<body>
{% cms_toolbar %}
{% placeholder base_content %}
{% block base_content %}{\% endblock %}
{% render_block "js" %}
</body>
</html>
And we can edit the templates/template_1.html
template
{% extends "base.html" %}
{% load cms_tags %}
{% block base_content %}
{% placeholder template_1_content %}
{% endblock %}
If you just did a fresh install of django projects run these commands to set up your database
$ python manage.py syncdb --all
$ python manage.py migrate --fake
If you want to fire up a webserver to test your local set up you can run
$ python manage.py runserver
Now you can open a browser window and go to http://localhost:8000/
In order to deploy to Heroku we’ll have to setup the database in the my_app/settings.py
# Parse database configuration from $DATABASE_URL
import dj_database_url
DATABASES['default'] = dj_database_url.config()
# Honor the 'X-Forwarded-Proto' header for request.is_secure()
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
Add a Procfile
file in your project root
web: gunicorn my_app.wsgi:
Finally add your Amazon credentials into settings.py
# Amazon S3 credentials
AWS_ACCESS_KEY_ID = os.environ['AWS_ACCESS_KEY_ID']
AWS_SECRET_ACCESS_KEY = os.environ['AWS_SECRET_ACCESS_KEY']
# Amazon S3 URL
AWS_STORAGE_BUCKET_NAME = '<your-bucket-name>'
S3_URL = 'http://%s.s3.amazonaws.com/' % AWS_STORAGE_BUCKET_NAME
# Static files location
STATICFILES_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
STATIC_URL = S3_URL
# Default File storage
DEFAULT_FILE_STORAGE = 'storages.backends.s3boto.S3BotoStorage'
MEDIA_URL = S3_URL
If you need to use Amazon S3 using http instead of https change this constant to False
AWS_S3_SECURE_URLS = False
You may alse collect your static files and upload them to Amazon S3
$ python manage.py collectstatic
Now you can push to Heroku and set up the database
$ git push heroku master
$ heroku run python manage.py syncdb --all
$ heroku run python manage.py migrate --fake
After adding a new plugin or changing your database you’ll have to execute
$ heroku run python manage.py syncdb
$ heroku run python manage.py migrate