Install and Deploy Django with MAMP using mod_wsgi

Getting Apache ready for serving Python applications seems to really be a headache. mod_python seems relatively easy, but the preferred mod_wsgi seems to give everyone headaches. I wanted to serve my python applications using MAMP since it's part of my daily workflow. I found a decent solution that is working really well for me with MAMP on OSX (Leopard). You may want to check out my previous post on installing and managing a basic OSX Django Stack before reading this one.

Installing WSGI

To install WSGI, you need to compile it against the version of Apache you'll be using it with. MAMP's current packaged version of Apache is 2.0.63, which is not super new, but will do. If you're like me and you just installed the MAMP binary instead of downloading the source code...well, then you don't have the Apache source code for 2.0.63, do you? So, let's get it!

I had already installed Macports in my previous adventure with Django installs. I decided to see what was available Apache-wise, and lo-and-behold:

$ port search "apache"
apache20 @2.0.63 (www)
    The extremely popular second version of the Apache http server

The exact same version that MAMP is packaged with! Awesome! Let's install it...

$ port install apache20

That'll install Apache in /opt/local/apache20 (or wherever Macports is installing stuff on your machine). Next you'll need to grab the mod_wsgi source from author Graham Dumpleton (thanks, Graham!). Unpack that tar.gz file and fire up terminal and cd into that folder. First read this code section:

mod_wsgi-3.2 $ ./configure

checking for apxs2... no
checking for apxs... /usr/sbin/apxs
checking Apache version... 2.2.14
checking for python... /Library/Frameworks/Python.framework/Versions/2.6/bin/python
configure: creating ./config.status
config.status: creating Makefile

So our basic configure checks for apxs (apache extension tool) and finds the default OSX install – which for me is currently 2.2.14; too new for MAMP. So go ahead and add the --with-apxs flag to the configure and point to wherever Macports installed your apache20:

mod_wsgi-3.2 $ ./configure --with-apxs=/opt/local/apache20/bin/apxs
checking Apache version... 2.0.63
checking for python... /Library/Frameworks/Python.framework/Versions/2.6/bin/python
configure: creating ./config.status
config.status: creating Makefile

Ok, so the Apache version looks right this time. Let's make and install that guy:

$ make
$ sudo make install
chmod 755 /opt/local/apache20/modules/mod_wsgi.so

Cool, so looks like it copied the compiled wsgi module into our apache20 installation. Now we just need to copy it to /Applications/MAMP/Library/modules (your MAMP modules folder).

Fire up MAMP Pro and go to File > Edit Template > Apache httpd.conf. Add the following after the other LoadModule directives:

LoadModule wsgi_module modules/mod_wsgi.so

Ok, that's the install. Stop and start MAMP services and you've got WSGI ready to serve python apps. Next step is to configure a Django site to be served.

Using WSGI

To start, I've commited my "learning" code to github, so you can check out how I'm learning how to set up and use Django on my machine. I'll be referencing these files throughout so grab them if you want them. I'm also assuming you've created a basic Django project and an application. My learning code uses the same code from the introduction tutorial on the djangoproject.com site. My sample code is in a directory called "project" and I have an application called "polls."

First thing you want to do is create a named host like you always do with MAMP. Switch to the hosts panel and hit the "+" button. I called this one "django.dev". In the General settings, point the document root to your project's root; in my case it points to /Library/WebServer/Documents/Django/project.

Now in your django project, create a folder called "apache" and create two files there.

/project/
    /apache/
        apache_django_wsgi.conf
        django.wsgi
    settings.py
    polls
    ...

See the two files and folder stucture on github here. django.wsgi is your primary wsgi application. This is mounted as the root of your website:

import os, sys

# path to parent folder of project
sys.path.append('/Library/Webserver/Documents/Django')
# path to your settings module
os.environ['DJANGO_SETTINGS_MODULE'] = 'project.settings'

# create a wsgi "application"
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()

You can see my setup here. apache_django_wsgi.conf is the httpd.conf file for your VirtualHost:

Alias /static /Library/Webserver/Documents/Django/project/static

<Directory /Library/Webserver/Documents/Django/project/media>
Order deny,allow
Allow from all
</Directory>

WSGIScriptAlias / /Library/Webserver/Documents/Django/project/apache/django.wsgi

You can see that mine defines an alias that points to a static folder (where I'll serve my js, css, images from for now) and a WSGIScriptAlias which is the full path to my .wsgi application.

Now back in MAMP, go to the advanced settings of your virtual host and in the "Customized virtual host general settings" add:

Include /Library/Webserver/Documents/Django/project/apache/apache_django_wsgi.conf

This would be the full path to your .conf file in your project. Again, restart MAMP's services. So now when you hit django.dev, the application defined in your .wsgi will be served. django.dev/static/ will be avaiable for you to add static content like js, css, etc. The end.

May 16th, 2010 | Permalink

Django "Stack" Install with ActivePython on Win/Mac

A current project involves Django, PostgreSQL, and git; three softwares I was pretty much unfamiliar with as a LAMP developer. After some poking around and initial love affair with Python and the idea of Django...well, Django is super-sweet on *nix OSs like Ubuntu, but not so fun to install and use on Windows and the "unix-like" Darwin-based Mac OS. So here's the start of my install guide for Windows. It can easily be applied to Mac since ActivePython is available for Mac as well.

So, the requirements: Python is easy to install; Django is easy to install; MySQL is generally pretty easy to install; the adapters that allow Python to talk to MySQL? Not so much. And what if you want to manage all those python modules you install? Or have virtual environments that match your target deployment environment? Enter ActivePython. ActivePython is essentially a distribution of Python and a number of other programs for managing python and python modules/package. I highly recommend you start with that:

Install ActivePython: http://www.activestate.com/activepython/

I just installed to C:\Python (/Python on Mac).

Now, the creators of the code I'm working with for this project use an application called "pip" (bundled with ActivePython) that allows you to install a list of dependancies from a standard requirements file. You can "install" packages, svn repositories, git repositories, and more. This is easily one of the coolest ways to distribute code I've ever seen. I fully expect this to be a standard development method in the next few years. Anyway, to import these files into pip require require you to have a command line version of git and subversion, so:

Install Git for windows

Options for the install:
- Install git as cmd line tool (not in bash shell)
- Checkout as-is, commit as Unix-style endings

Install Git for OSX

Install Subversion Command line client (CollabNet Subversion Command-Line Client v1.6.11 (for Windows))

On OSX you should have svn already and you shouldn't need to worry too much about line endings. Feel free to upgrade to the latest and greatest.

Now we have what we need to get going: from ActivePython; virtualenv, pip, and pypm; svn; and git.

Make sure you can run both. Open up a cmd prompt or Terminal on OSX:

$ git --version
git version 1.7.0.2.mysysgit.0

$ svn --version
svn, version 1.6.11

Ok, we're good to go. Switch to your drive root or wherever you want to create your virtual environments:

$ mkdir virtualenvs
$ cd virtualenvs

# create a virtual enviroment called "myenv"
$ virtualenv myenv

# OR, if you want the env to not inherit your globally installed python site packages
# which you probably want since installing mysql and postgre plugins in a virtual
# environment is tough since you have to compile them
$ virtualenv --no-site-packages myenv

# activate the environment (windows):
$ myenv\Scripts\activate.bat
(myenv)D:\virtualenvs>

# activate the environment (mac):
# note that scripts are created in "bin" instead of "Scripts"
$ source myenv/bin/activate
(myenv)virtualenvs $

Now running pip will use the pip created when the virtual environment was created, installing packages only in that working environment. So you can have different environments with different packages installed.

Let's install Django as a test first.

# latest
(myenv)virtualenvs $ pip install Django

# or install a specific version
(myenv)virtualenvs $ pip install Django==1.1
Downloading/unpacking Django==1.1
  Downloading Django-1.1.tar.gz (5.6Mb): 5.6Mb downloaded
  Running setup.py egg_info for package Django
Installing collected packages: Django
  Running setup.py install for Django
Successfully installed Django

Next step in my install process was getting the codebase from the client. They used github for version control (replacing client name with dummy copy):

# clone the git repository
(myenv)virtualenvs $ cd D:\Projects\Client\
(myenv)virtualenvs $ git clone git@github.com:client/repository.git

The client's repo had a requirments formatted file that I can then use to install with pip.

# back in our virtual environment, now install the requirements
# the -E flag tells pip which environment to install to.
(myenv)virtualenvs $ pip install -E myenv -r D:\Projects\Client\repository\requirements.txt

This is neat because pip's requirements format allows svn, git, and pypm (pythom package manager) hints in this file. It'll automatically pull in the dependancies using the method specified. Here's an example:

Django==1.1
-e svn+http://django-mptt.googlecode.com/svn/trunk@121#egg=django_mptt-0.3_pre-py2.5-dev
django-flatcontent==0.1.2
-e git://github.com/bartTC/django-frontendadmin.git@53d8ed1fdcd1ef466fb9c8b38ccb2abb77978b1e#egg=django_frontendadmin-0.5-py2.6-dev
django-markitup==0.5.2
django-haystack==1.0.1-final
Whoosh==0.3.9
textile

So we're installing Django 1.1, copying down an svn repo from googlecode, cloning a git repo from github and installing a number of python mods using PyPm. Pretty badass for one command!

If we were on unix or mac (with xcode installed) we could also use pip to compile the mysqldb module, but we have some binary install options on windows. This will install it for all python environments. Not sure how to use this to install to a specific virtual environment: Download MySQL-python-1.2.2.win32-py2.6.exe (1,022.8 KiB). Run the installer and select your ActivePython install when prompted. To test if it works, open cmd prompt and type

$ python
>>> import MySQLdb 

If there's no errors; hey, it worked. On MacOS, it's not quite as fun. I used Macports to download the MySQL5 headers, then I did the following:

# only download the package
(myenv)virtualenvs $ pip install --no-install MySQL-python

Then open the downloaded package and edit site.cfg and uncomment line 13 and add the path to your mysql_config (for me this ended up pointing to the bin folder and mysql_config I downloaded with Macports). After than you can run:

python setup.py build
python setup.py install

There's also a Windows port of the psycopg2 module (PostgreSQL for Python). We happen to be using this for the client project. You'll need to install Postgre 8.x first. Then install this guy. Not going to go into Postgre installation and whatnot since I only know a bit of the basics myself. It was enough to get my Django project up and running:

cd /Projects/Client/repository/web
python manage.py syncdb
pyhton manage.py runserver

Command line is fun. Now, getting WSGI to work with MAMP will be the real challenge.

May 14th, 2010 | Permalink