As promised in my previous entry. I will go through automating the entire ordeal that is, to setup a django developing environment with mod_wsgi. This run-down comes with a gist which you can find here.
Seeing that i already went through what we needed, I'd suggest you read this post before proceeding.
This was made on OS X, you might want to change a few things if your running on a different distro. Now assuming you've already read it and have setuptools installed lets go ahead and get fabric.
sudo easy_install fabric
Hop into a directory you want to work from and create a fabfile.py. Consider the fabfile a configuration file. Basically a fabfile consists of python functions as you will see in a minute.
Start it like you would any other python script and import the fabric api.
#!/usr/bin/env python
from fabric.api import *
The fabric api comes with a powerful dictionary subclass for you to put variables called env, read more about it here. If we were for example going to define our project name and have it accessible to fabric we would go about defining it like so
env.hosts = ['localhost']
env.projectname = 'test_project'
run('mkdir %(projectname)s') % env
Hosts is required since fabric assumes that you are running commands on a remote host, for this example to work you will have to enable ssh.
So without further ado lets get into it. We'll go ahead and and create a function that holds what we need for our local setup to work.
def local():
"""your local setup"""
env.hosts = ['localhost']
env.user = 'username'
env.password = 'secret'
env.projectname = 'test_project'
env.workspace = '/Users/%(username)s/Sites' #name of workspace dir
env.path = '%(workspace)s/%(projectname)s' % env
env.activate_path = '%(workspace)s/%(projectname)s/bin/activate' % env
env.apache_path = '%(path)s/apache' % env
env.httpd = '/private/etc/apache2/httpd.conf' #path to where your apache's httpd.conf is located
env.ip = '127.0.0.1'
Now this is pretty straight forward, we define variables that we will later need, these come in handy since we only have to define them once. When running our fabfile we simply write out fab local and these variables will be available to fabric.
I'll now go ahead and create our setup function in accordance with my previous post.
def setup():
"""docstring for setup"""
require('hosts', provided_by=[local])
require('path')
with cd(env.workspace):
run('virtualenv --no-site-packages %(projectname)s' % env)
sudo('easy_install pip', pty=True)
run('source %(activate_path)s; pip install django' % env)
with cd(env.path):
run('source %(activate_path)s; django-admin.py startproject %(projectname)s' % env)
run ('mkdir %(path)s/apache' % env )
run('mkdir %(apache_path)s/logs; touch %(apache_path)s/%(projectname)s.conf; touch %(apache_path)s/%(projectname)s.wsgi' % env)
We've used the with statement which keeps the directory state, in this example we stay in the workspace directory and run the next commands there. Read more about context managers here. So far we've initiated a virtualenv directory and in it activated our path, used pip to install django and ran startproject. We've also created a directory "apache" and in it created two files, a wsgi and a conf file.
Normally I this would be sufficient, we could manually write apache.conf and wsgi.conf. But lets go ahead and use fabric to write these. Create a new function that uses pythons built in write functions.
def write_wsgi():
"""docstring for write_wsgi"""
file = open("%(apache_path)s/%(projectname)s.wsgi" % env, "w")
file.write("import os, sys\nsys.path = ['%(path)s'] + sys.path\n\n\nos.environ['DJANGO_SETTINGS_MODULE'] = '%(projectname)s.settings'\n \n\nimport django.core.handlers.wsgi\napplication = django.core.handlers.wsgi.WSGIHandler()" % env)
file.close()
def write_conf():
"""docstring for write_conf"""
file = open("%(apache_path)s/%(projectname)s.conf" % env, "w")
file.write("WSGIPythonHome '%(path)s'\nWSGIRestrictStdout Off\nWSGIDaemonProcess %(projectname)s\nWSGIProcessGroup %(projectname)s\n\n<VirtualHost *:80>\n ServerName %(projectname)s.local\n Alias /site_media/ '%(path)s/%(projectname)s/site-media'\n<Directory '%(path)s/%(projectname)s/site-media'> Order allow,deny\n Options Indexes\n Allow from all\n\n</Directory>\n\n\n\nAlias /media/ '%(path)s/lib/python2.6/site-packages/django/contrib/admin/media/'\n<Directory '%(path)s/python2.6/site-packages/django/contrib/admin/media/'>\n Order allow,deny \n Options Indexes \n Allow from all \n</Directory>\n\nWSGIScriptAlias / '%(apache_path)s/%(projectname)s.wsgi\n\n<Directory '%(apache_path)s'>\n Allow from all\n</Directory>\nErrorLog %(apache_path)s/logs/%(projectname)s-error_log\nTransferLog %(apache_path)s/logs/%(projectname)s-access_log\n</VirtualHost>" % env)
file.close()
Here we use the env variables to do some string formatting. This saves a lot of time. Fabric also comes with some file and directory management tools which we could have used. These live in the contrib. Go ahead and import the append function from fabric.contrib.file import append
To demonstrate this we'll use it to enable our site, ie. include projectname.conf to apaches httpd.conf.
def enable_site():
"""this enable your site using httpd.conf"""
append('#enabling %(projectname)s\nInclude %(apache_path)s/%(projectname)s.conf\n' % env,'%(httpd)s' % env, use_sudo=True)
append('%(ip)s %(projectname)s.local' % env, '/etc/hosts', use_sudo=True)
To append the httpd.conf file we need to be sudo, this is easy with fabric's use_sudo option. We've also added our site to the /etc/hosts file which anable's us to use local dns lookup for our site.
Last but not least since we really like using wsgi for development and the trick to get this working needs a script called monitor inside our django project. I've put up a gist file at github.com we'll create a function that gets this and put's it into our django project directory.
def get_monitor():
"""download and enable auto restart of wsgi"""
run('cd %(path)s;git clone git://gist.github.com/258020.git gist-258020' % env)
run('cd %(path)s/gist-258020; mv monitor.py %(path)s/%(projectname)s/; rm -rf %(path)s/gist-258020' % env)
append("\nimport %(projectname)s.monitor\n%(projectname)s.monitor.start(interval=1.0)" % env,"%(apache_path)s/%(projectname)s.wsgi" % env)
And there we go, we simply download the gist, extract the content and place it in the right directory. We've also used append to add it to wsgi.conf
What we now have achieved is automating the process of setting up a local django developing enviroment using wsgi. From here it's pretty easy to setup a remote_server function to hold those env variables & a deploy function.
I've put up a gist for you to download http://gist.github.com/278999. In the same directory as the fabfile just run fab local setup. It should presumably run flawlessly, restart apache, point your browser to projectname.local and you should be presented with django's welcome page.
Latest tweet
The most expensive burgers I ever had, this better be worth it. — at Burger & Bun http://gowal.la/c/2r2qB?137Copyright {Feisal Adur} 2009. 