22

Mar

Filed in Django, How-To's with No comments |

Today a question was raised on how to deploy Django on your server. I figured it’d be useful to put together a quick how-to for deploying Django on your standard LAMP infrastructure. I’m not going to say the way we’ve done things is the best, or if it’s even common, but it’s the way we’ve handled it.

Choosing the Right Software

Most importantly when deploying Django you want to use the right architecture for the server. After a lot of trial and error, with much software, I’ve been pretty happy with what I’ve setup on my local server.

  • Apache 2.x + mod_wsgi
    You can see my configuration example.
  • MySQL 5.0.x (or Postgre 8.2.x if you’re a fan)
  • Python 2.5
    If you have a choice, there’s no reason to use old software.
  • Django (trunk)
    I suggest you start with trunk. It’s very stable and you won’t have to deal with backwards incompatibility.
  • (Optional) memcache
    If you need caching, don’t waste your time with anything other than memcache.
  • (Optional) Jinja Template Engine
    If you prefer more logic and speed in your templates, I highly recommend the Jinja Template Engine.

Project Structure

This is one area, which is still up for heavy debate. It seems to be done in a multitude of ways, and even I myself seem to do it in such. iBegin we’ve set up each project in idea that the python code should not be in the same base directory as the templates and media. So for iBegin we end up with a project structure like so:

/project_name/
/project_name/templates/
/project_name/media/
/project_name/project_name/
/project_name/project_name/manage.py

Now to take a step back, in PHP I learned to separate includes (templates and media) from my codebase, to prevent them from being web accessible. This concept comes from that learning. The main issue I’ve seen arise from this is that the pathing can be very confusing, especially when checking python paths. For iBegin Places we actually have /places/ and then inside of that we have another project, called zillow, so /places/zillow/. This gets to be pretty hectic when you’re trying to solve PYTHONPATH issues.

On my local server (which hosts this blog), I’ve setup things a bit differently:

/project_name/
/project_name/templates/
/project_name/media/
/project_name/manage.py

This concept came from the idea of keeping everything simple, and having an easy PYTHONPATH (the user’s base directory for example).

local_settings.py

First things first, before deploying anything, let’s talk about local_settings vs settings. One of the biggest issues with deployment, on any kind of website, is that your settings differ from developing, to staging, to live. There’s a pretty good snippet that I grabbed a while back from djangosnippets.org for this.

try:
    from local_settings import *
except ImportError:
    pass

You would place this within your settings.py near the end of the file. What this does is look for a file called local_settings.py in the same directory as settings, and if it exists, and causes no errors, will import all of the settings in there.

If you are using subversion you’re also going to want to svn:ignore on local_settings.py. I would also recommend versioning a local_settings.tpl, and using a symlink for your local_settings.py rather than keeping it in the project directory.

Managing Subversion

One of the biggest changes I’ve made lately to the way we deploy projects is relying heavily on subversion. Over at Curse we started by having a live branch, and merging into that, and then rsync’ing that to the servers. While this worked fairly well and all, it was a pretty tedious approach to deal with merging in SVN.

Eventually at Curse we switched over to using tags, which is what we’ve been doing lately over at iBegin, is using tags pretty strictly. We tag every single release, and for the most part, you’ll always find a specific tagged version on the live website. In my opinion, this was the most concise and easiest solution for making subversion work.

Setup Staging

For staging we keep it pretty simple, and just have a svn checkout for the current project where it needs to be. Being that staging is usually right before you release it to the live site, this works very good for making sure trunk is fit. A simple example of how we update staging (this is contained within scripts to be precise):

ssh dev.ibegin.com
# updatesite.sh <project>
svn up /home/ibegin/$1
sudo apachectl graceful

Or if you were using mod_wsgi:

svn up /home/ibegin/$1
killall -u $1 apache2

Releasing Versions

The biggest issue then comes with when you want to update your website. Previous methods I’ve used would be to SCP the contents of the site over, or have an SVN checkout on the actual live server which then does some kind of update. This time around I decided on a much more sane solution: svn export.

It made it extremely simple for updating the website, as all you would do is call an svn export --force and an apache graceful (or kill the procs with mod_wsgi). This doesn’t solve the multiple server aspect, but you could run a script to svn export and then rsync similarly to how we did it on Curse. So here’s an example push (using iBegin’s logic):

ssh ibegin.com
# /home/ibegin/places is where our checkout would be
# If you weren't using tags, you could replace this with your trunk
svn export https://svn.ibegin.com/ibegin/places/tags/0.3 /home/ibegin/ --force

This is pretty self explanatory, but here’s the steps involved:

  1. First we SSH into our live web server
    ssh.ibegin.com
  2. Once we’re in the server; we do an svn export on our branch, tag, or trunk, and a force update into the live directory. Without the force tag it would throw an error because the directory already exists.
  3. svn export https://svn.ibegin.com/ibegin/places/tags/0.3 /home/ibegin/ --force

That’s all there is to it. It sounds complicated at first (if you’re unfamiliar), but it’s really simple to deploy Django and release your project.

No Responses to "How to Deploy Django with Subversion and mod_wsgi"

Subscribe to this topic with RSS or get the Trackback URL

Leave A Reply

 Username (*required)

 Email Address (*private)

 Website (*optional)

Note: Comments moderation may be active so there is no need to resubmit your comment.