include "../_i/1.h"; ?>
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.
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.
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.
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).
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).
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.
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.)
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.
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.
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.
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).
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>
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/"
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.
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.
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.
include "../_i/3.h" ?>