Moving into production

At some point, every Django-based project (hopefully) moves out of the development phase and into production deployment, and this can be a traumatic experience. As a result, there are a few things you’ll nearly always want to do during this process in order to transition smoothly and ensure you go to production with all your code humming along; this time around we’ll look at a few of the more common items, and if I miss out on something you’ve found useful, feel free to mention it in a comment.

General settings changes

First and foremost, you want to flip your DEBUG setting to False; I’d hope this is obvious, but I’ve seen enough people move to production with DEBUG still on that it’s worth mentioning explicitly. Turning DEBUG off brings several immediate benefits:

  1. Django will stop displaying full tracebacks with code and settings whenever it encounters an internal error, which keeps the general public from getting a sneak peek into your application.
  2. Django will stop keeping a log of the database queries you’ve executed; when you’re debugging, this is useful, but in production it’s a resource drain you don’t want.
  3. Anything you had in your templates which keyed off the debug variable (set by the debugging context processor if you’re using a RequestContext in your view) will stop displaying, which provides a handy way to ensure that extra debugging info in your templates only displays when you’re actually debugging.

There are a couple other settings you’ll want to look at or double-check when going live:

  • Fill in values for the ADMINS and MANAGERS settings if you haven’t already; Django will use these settings to email useful information (including tracebacks and notifications of broken links) to your site’s staff.
  • Make sure the email-related settings are correct, particularly DEFAULT_FROM_EMAIL and SERVER_EMAIL, because many email providers will reject email which claims to come from “webmaster@localhost” or “root@localhost” (the default values of these settings) or which doesn’t come from accounts which verifiably exist. Additionally, if you don’t have a correctly-configured mail server and the proper settings to tell Django to use it, you’ll never get emails about errors on your site, or any other email generated by Django.
  • If you’ve changed the value of TEMPLATE_STRING_IF_INVALID, you should set it back to an empty string; some templates (particularly in the admin) don’t react well to having a debugging string displayed when they expect silent variable failure.
  • Fill in INTERNAL_IPS so Django will know which IP address(es) correspond to your company or otherwise “internal” computers which can safely see some types of information (like the information retrieved by the admin documentation bookmarklets).

Dealing with caching

Django’s caching framework, when enabled via the CacheMiddleware or accessed via per-view decorators or its low-level API, will cache content regardless of the value of the DEBUG setting (because, after all, you’ll often need to test performance with and without caching before going live), which raises a tricky question of how to avoid caching in development but have it enabled in production (because just as often you’ll want to bypass the cache and have changes show up immediately while you’re developing a site).

There are several methods you could use to handle this, but probably the most effective is simply to toggle the value of the CACHE_BACKEND setting; the ideal is to switch between the “dummy” backend in development and your actual caching mechanism in production. The “dummy” backend doesn’t actually cache anything, but will satisfy the need to have CACHE_BACKEND set when using the cache API or middleware, and you can even put a conditional check into your settings file to have the change happen automatically:

if DEBUG:
    CACHE_BACKEND = "dummy:///"
else:
    CACHE_BACKEND = "memcached://127.0.0.1:11211/"

Making sure errors work properly

Aside from setting up the ADMINS and MANAGERS settings to ensure that various types of errors are emailed to your site staff, you’ll also want to make sure you have two templates available in the top level of one of your template directories:

  1. 500.html will be used for internal errors which generate an HTTP 500 error; it has no context, not even the variables which would be populated by a RequestContext, because it doesn’t use that; in the event of an internal error, it’s not possible to rely on anything, including RequestContext (which needs to do database queries and introspect the HttpRequest, two things which could easily fail if something’s already errored out).
  2. 404.html will be used for any URL which doesn’t resolve, or whenever something raises an uncaught Http404 exception. It uses a RequestContext and so will apply context processors, and will also have the variable request_path available, containing the URL which generated the 404.

If these templates are missing, the actual error will be masked by a TemplateDoesNotExist raised when they’re not found, a situation which occasionally trips up newcomers to Django. The specific template names come from the views Django uses in these cases: django.views.defaults.server_error for a 500, django.views.defaults.page_not_found for a 404. You can override these in your root URLConf by assigning the dotted Python paths (as strings) of your own error-handling views to the variables handler500 and handler404, respectively.

Getting your sites straight

If you’re using Django’s sites framework (which gets listed in INSTALLED_APPS by default), an initial Site object titled “example.com” was created for you during syncdb. You generally do not want to delete this object, because code which uses the sites framework (including the admin application) relies on the existence of a Site object with an id the same as the value of the SITE_ID setting. Instead, it’s best to edit the initial Site object to reflect the domain or IP address on which you’re doing development, and then change it to your live domain when you go into production.

You should also make sure that you haven’t inadvertently copied over the SITE_ID setting from another settings file, or filled in an incorrect default value. And if you’re administering multiple sites from one project that’s running an instance of the admin, you’ll want to ensure that you’ve filled in the ADMIN_FOR setting in that project, so it’ll know that its instance of the admin is responsible for the other projects as well.

And a lot more

Everybody’s experience of going live is different, and these are just some of the most common things people seem to encounter; if you’ve run into specific problems or useful tricks, feel free to share them in the comments below.

Comments

Pete
November 8, 2007
#

James, thanks so much for all the tips. Your blog has been invaluable to me in learning Django.

One hitch I ran after deployment was that I wasn’t getting email notifications of errors, despite having DEFAULT_FROM_EMAIL set.

For me, SERVER_EMAIL was the one I needed to set in order have them sent from a legitimate address.

— Pete

James Bennett
November 9, 2007
#

Yeah, I just fixed that.

Antti Rasinen
November 9, 2007
#

You have a typo in the Caching section: CACHE_BAKEND.

Mike Howarth
November 9, 2007
#

Yet another great post James.

This will come in very useful for me as I’m just about to put my first Django app in to product.

Keep up the great work!

Bernd Essl
November 9, 2007
#

On the djangoproject.com trac there is a trick to load different settings runing on production or development servers. http://code.djangoproject.com/browser/djangoproject.com/django_website/settings.py

DEVELOPMENT_MODE = (platform.node() != “djangoproject”)

djangoproject” is the hostname of your production server.

Andrews Medina
November 9, 2007
#

Hi James,

Congratulations!

I can translate yours posts to brazillian portuguese?

d.
November 9, 2007
#

From my experience: 1. Test if mailing error reports works. 2. Make sure that SEND_BROKEN_LINK_EMAILS is set - at least for some time after moving to the production envirnoment. 3. Most important - for development use the same envirnoment as for production. Or as close as possible.

James Bennett
November 9, 2007
#

Andrews, you want to read this.

cosa
November 9, 2007
#

Thanks James!

Andrews Medina
November 9, 2007
#

James Bennett, I read this copytight and will be translate some posts to brazilian portuguese.

Fred
November 13, 2007
#

James, great blog - thanks for sharing.

Stupid question: How do you transition between revisions of a site? That is: change the code, add new graphics, do you use an a/b directory structure and swap via an alias?

Any general principals you use, or pointers would be appreciated.

Max Battcher
November 20, 2007
#

Fred:

I don’t know about James, but here is the best general transition tip just about anyone will give you:

Source Control. (Source Control, Source Control, Source Control!) Learn a good system (in a particular order of my own opinion: SVN, Mercurial, Git, Darcs) and use it religiously. With a good source control system you don’t really need a a/b production site switch, just rely on your source control system to handle the switch between revision a and revision b, which is a job that source control systems are designed for. In any and every sort of software design, a good source control system is your best friend and it makes everything about a transition easier to handle: moving changes from development servers to production servers, knowing which changes are where, knowing when changes were made (and by whom), undoing faulty changes, etc…

Whatever-ishere
November 21, 2007
#

thanks for the GREAT post! Very useful…

Fred
November 22, 2007
#

@Max

Yeah source control is a given. Apols I was not specific enough in my question. I meant more in the actual deployment from source control and switching from the current to next release. Have been doing digging and Capistrano (despite being Ruby and Rails focused) looks to have some nice recipes for doing this. They take an A/B directory approach a step further having releases directory into which each new release is exported into, then symlinking ‘current’ to the latest release.

see http://www.capify.org, also mentioned in the Django Master Class slides.

Add a comment

You may use Markdown syntax in your comment, but raw HTML will be removed. By posting a comment here, you are agreeing to the terms of my comment policy.