Serving Django Projects (Revisited)
After reading the comments on my last post on the subject, I realized there was definitely some room for improvement in my strategy. This is take two of the original post.
Problems
My original strategy had a couple of downfalls:
- Poisoning the Python Path
I was adding directories to the Python Path that weren’t Python. This raised the chance of namespace collision and just wasn’t a very clean way to do things. - No project source repository
I was still storing all my source files in one big folder. Tracking which project is using what was more difficult than it needed to be.
Solutions
The first step to recovery was forgetting about sharing libraries between projects altogether. In theory it sounds great, in practice it was cumbersome to manage. My directory structure now looks like this:
|-domain1.com |--apache |---django.wsgi |--src |---domain1_project_src |---third_party_repo1 |---third_party_repo2
This is much cleaner and allows for simple control over the versioning on third party repositories. For source with stable APIs, like Django 1.0, I still place it in /usr/local/src, allowing me to update all sites using the library in one go without worrying about breakage.
Virtualenv is Your New Best Friend
As recommended in the comments on the last post, if you’re hosting multiple projects on one box, virtualenv should be a requirement. Install it on your development machine too. You’ll kick yourself for not using it sooner. Grab virtualenvwrapper while you’re at it too.
After installing and getting a feel for how it works, you can plug it into mod_wsgi. The trouble is it works slightly differently with virtualenv than your interactive sessions. It imports the global site-packages first and then your virtualenv. The other option is a directive to load an empty virtualenv on startup. This hung me up a bit. I need libraries like psycopg2 and PIL and didn’t want to have to build them for each project, but the global site-packages had all sorts of cruft living in it that I didn’t want. I decided to strip it down to the bare essentials and my new policy is that only libraries that I can apt-get live in the global site-packages.
With all this in place, I symlinked the proper modules from domain1.com/src/ into $VIRTUALENV/lib/python2.5/site-packages and as long as I have a clean global python path, I’m good to go in either mod_wsgi or an interactive shell.
What About Static Files?
Not being a server guru, I was pretty proud of myself after I got all this running. There was one rather large wart though. My static files were living in domain1.com/src/domain1_src/domain1/static. For most sites, users were uploading files into a directory that was under version control and not writeable by the web server by default. Thanks to a suggestion from Vlada Macek, I put them where they belong in /var specifically, /var/www/domain1.com. I have a folder in there for uploads and symlinks to static, admin or any other site specific static files.
Suggestions?
I’m really happy with the new setup and it makes server management considerably easier than the mess I considered “stylish” earlier. What about you? If there are better techniques, I’d love to hear them. I’ll try to follow up with some Nginx and Apache configs soon.
Comments
Got something to say?
This was written on September, 22 2008 and is filed in django.
Our Products
Categories
- SEO
- accessiblity
- code
- company news
- django
- gondola
- portfolio
- presentation
- screencast
- software
- subversion
- trailmapping
- wordpress
Archives
- December, 2008
- November, 2008
- September, 2008
- August, 2008
- July, 2008
- June, 2008
- May, 2008
- April, 2008
Elsewhere
What we’ve been up to online
-
committed to lincolnloop/django-beancounter
Pete, 15 hours, 44 minutes ago -
pushed to master at lincolnloop/django-beancounter
Pete, 15 hours, 44 minutes ago -
committed to lincolnloop/django-beancounter
Pete, 15 hours, 44 minutes ago -
committed to lincolnloop/django-beancounter
Pete, 15 hours, 44 minutes ago -
committed to lincolnloop/django-beancounter
Pete, 15 hours, 44 minutes ago -
committed to lincolnloop/django-beancounter
Pete, 15 hours, 44 minutes ago -
applied fork commits to lincoln-loop-deploy/master
Pete, 1 week, 5 days ago -
Anybody used www.earthclassmail.com? I'm considering routing my business mail through them.
Pete, 1 week, 5 days ago -
Having trouble motivating for work after taking the morning off to ski. Over 20" of new snow overnight. Pow!
Pete, 1 week, 5 days ago -
iMovie HD 6
iMovie '08 lacks some important features found in the previous version. Luckily '06 is available as a free download
Pete, 1 week, 6 days ago -
Brizzled: Python, sys.path and EasyInstall
Use site.addsitedir instead of sys.path.append to properly add a virtualenv to your python path
Pete, 2 weeks ago -
Need to spam filtering on my blog comments and for licensing reasons, Akismet is out. Anybody have a good Django Defensio implementation?
Pete, 2 weeks ago -
Awesome... 1. type lengthy message in Basecamp. 2. step away to take a phone call. 3. return to a spinning beach ball in Safari
Pete, 2 weeks, 3 days ago -
I'm blown away by the customer service at www.tirerack.com. They are the Zappos of auto tires.
Pete, 2 weeks, 3 days ago -
YouTube - SCRUM in Under 10 Minutes (HD)
Pete, 2 weeks, 3 days ago


yes!
i downloaded the virtualenv and it works quite good for me!
thanks for sharing.
This is our current repository layout at distrop:
project_name/ media/ <- not versioned, used for development, could be anywhere on the filesystem really/
static <- symlink to static content
project_name/
__init__.py
models.py <- project specific models
settings.py
templates/
templatetags/
urls.py
views.py <- project specific views
README <- details on dependencies etc
static/ <- images, css, scripts
The projects are deployed in a per-project user’s home directory (we’re serving content using nginx+fastcgi) like so:
/home/project_name/projects/project_name/ <- the 'projects' directory is a little redundant, we know /home/project_name/media/ /home/project_name/media//
/home/project_name/media/static <- symlink to the static directory in the project
We install mature apps and dependencies with the help of setuptools and keep a site-packages directory on a per-user basis for less mature code.
Thanks for sharing this. This really made virtualenv click for me!