Deploying Django
Deploying and scaling live dynamic websites is a topic easily big enough to fill an entire semester or more; we're just going to barely scratch the surface.
The database
We've been using the SQLite database, which is great for development. It keeps all its data in a single file, right there in your project directory, so you don't have to worry about database users, permissions, configuring a database server, etc.
So why not just deploy with SQLite? SQLite doesn't support concurrency. In other words, you get more than one person using your website at the same time, and one of them is likely to get "database locked" errors. Not good.
Picking a database server
We need something more robust than SQLite. Commercial options include Oracle or Microsoft SQL Server, but we don't have tens (or hundreds) of thousands of dollars handy at the moment.
Fortunately, there are free open-source alternatives that are more than capable of handling the needs of a dynamic web site. The two most popular open-source options are MySQL and PostgreSQL. I prefer Postgres because it is stricter about ensuring data integrity. MySQL has a reputation for being easier to administer. Either would be a fine choice for most websites. For today we'll use Postgres, but from the Django side using MySQL wouldn't be much different.
Creating your database
Since this isn't a class on database server administration, I've
gone ahead and set up Postgres on dj.goshen.edu, and created an
account for each of you, with the same username as your system shell
user (and your password same as the username - don't do this
normally). From the dj.goshen.edu shell prompt, use the Postgres
utility program createdb to create yourself a
database: createdb yourusername (to keep things simple,
we're making your database name the same as your username also).
Changing your DB settings
In your settings.py file, you have a set
of DATABASE_* settings telling Django what database to
use. We'll need to change these for your live site, to use Postgres
instead of SQLite. But you'll still want to use SQLite for
development.
How can we have different database settings on two different clones
of the same code? One possibility is to just change them in the "live"
clone, and never commit or pull from that clone. I use a more general
solution: I move the "default" settings into a file
called global_settings.py, and then have a very
simple settings.py file that imports all the settings
from global_settings and overrides whichever ones it
needs to for that particular deployment. I put this
simple settings.py in .hgignore so it never
gets committed in Mercurial (thus it can be different for each
clone).
Making global_settings happen
In the directory where your settings.py file lives,
run: hg mv settings.py global_settings.py Commit this,
then create a new file settings.py with the following
single line:
from global_settings import *
Add this settings.py file to
your .hgignore (so it doesn't show up in hg
status), and commit that change as well. For now this is all we
need; everything will work the same as before, except you'll need to
create this short settings.py wherever you run this
code.
Create a "live" checkout
From a dj.goshen.edu shell, run the following commands to set
yourself up a www/ directory in your homedir. This is
where we'll put all your live web code.
$ deactivate $ cd $ mkdir www $ cd www
Once you're inside your ~/www/ directory, use hg
clone to get a fresh clone of your codebase. You don't want to
be developing on the same code that's running your live site!
Run virtualenv yourproject_env to get yourself a fresh
virtualenv for the live site, activate the new env, and then pip
install -r requirements.txt to get all your dependencies (you
have been keeping that up to date when you install new things,
right?). (You don't actually have to easy_install pip
anymore; the new version of virtualenv automatically includes pip; but
it doesn't hurt if you do.)
A place for the database settings
Now create a settings.py in your live clone that looks
something like this:
from global_settings import * DEBUG = False TEMPLATE_DEBUG = False DATABASE_ENGINE = 'postgresql_psycopg2' DATABASE_NAME = 'yourusername' DATABASE_USER = 'yourusername' DATABASE_PASSWORD = 'yourusername' DATABASE_HOST = 'localhost'
This imports all the default settings, then overrides the database
settings so it will use your Postgres database (and to turn DEBUG off;
a live deployment with DEBUG on will use up memory over time). You
should now be able to run python manage.py syncdb
(and migrate if you're using South) in this live clone
without errors.
Hooking up Apache
In development, we've been using python manage.py
runserver as our web server. Great for development, even
auto-reloads when your files change. Just like SQLite, it's not good
for a real deployment: it also only supports a single user at a time,
and is relatively slow to boot. Instead, we'll use by far the most
popular webserver on the
internet: Apache.
apache.conf
To hook up your project to Apache, you'll need two new files: an
Apache config file, and a WSGI script file. Create the Apache config
file at ~/www/apache.conf; it can look like this for
now:
<VirtualHost *:80>
ServerName yourusername.dj.goshen.edu
WSGIScriptAlias / /home/yourusername/www/yourprojectclone/deploy.wsgi
</VirtualHost>
Obviously replace yourusername
and yourprojectclone with the appropriate names.
deploy.wsgi
WSGI is the Web Standard Gateway Interface, a Python standard that dictates how web servers communicate with Python web application code. Your WSGI script file is a sort of "entry point" into your application. For now, just copy mine from my feedback project and place it in your project at the top level next to requirements.txt. The only things in it you'll need to change are the name of your virtualenv in the fourth line, and near the bottom where it sets DJANGO_SETTINGS_MODULE to 'feedback.settings', replace 'feedback' with the name of your project directory (the directory containing settings.py).
Serving media
If you look in your urls.py, you'll see the section
that serves your media files is wrapped in if
settings.DEBUG:. DEBUG is now False, so Django won't serve
your media. There's good reason for this; when you have a fast
webserver like Apache available, tuned to serve up static files
super-quickly, it's very inefficient to go through Django for all your
media files; better to just have Apache serve them directly. So let's
set that up by adding this to your apache.conf file:
<VirtualHost *:80>
ServerName yourusername-media.dj.goshen.edu
DocumentRoot /home/yourusername/www/yourprojectclone/yourproject/media/
Alias /admin/ /home/yourusername/www/yourprojectclone/your_env/lib/python2.6/site-packages/django/contrib/admin/media/
</VirtualHost>
Telling Django where to find your media
We also need to tell Django that your media is available
at http://yourusername-media.dj.goshen.edu/ rather
than /media/. Just add this to your
new settings.py file along with the database
settings:
MEDIA_URL = "http://yourusername-media.dj.goshen.edu/" ADMIN_MEDIA_PREFIX = MEDIA_URL + "admin/"
Fire it up!
At this point, someone with administrator rights on dj.goshen.edu (either Paul or I) needs to hook up your apache.conf file into apache, and tell it to reload its configuration files. Once that's done, you should be able to visit http://yourusername.dj.goshen.edu and see your site.
Telling Apache to reload your code
Unlike runserver, Apache doesn't automatically reload
your code anytime the files change. If you commit some new features
and pull them into your live clone and update, you still won't see
them on the live site. To get Apache to reload your code, you just
touch the WSGI script file: touch deploy.wsgi, and it'll
reload.
Moving beyond dj.goshen.edu
If you want to deploy your site for the real world to use, you won't be able to use dj.goshen.edu (it might go away sometime after this class ends?). You'll have to pay for real web hosting. For a small site, my top recommendation is Webfaction.com: they have shared hosting plans from $5/mo and up, and they explicitly support Python and Django (many cheap web hosts only allow PHP).
If your site gets popular, you might need to move beyond shared hosting and get your own VPS (Virtual Private Server -- that's what dj.goshen.edu is). They typically cost $20/mo and up. With a VPS, you get better performance and more system resources than with shared hosting, but you have to do all the system administration yourself. I use (and am happy with) Linode; other popular providers include Slicehost and Rackspace Cloud.