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.
Reader Comments
Got something to say?
This was written on September, 22 2008 and is filed in django.
Our Products
Categories
- portfolio
- code
- software
- company news
- trailmapping
- SEO
- wordpress
- gondola
- presentation
- accessiblity
- subversion
- django
Archives
Elsewhere
What I’ve been up to online
-
A List Apart: Articles: A More Useful 404
17 hours, 32 minutes ago # -
I'm strongly considering ditching Backpack in favor of Google Apps
1 day, 12 hours ago # -
Scratching my own itch: "Drive-by" comments for git repos. No diffs, no patches, just click & comment. http://tinyurl.com/5kmos8
2 days, 7 hours ago # -
Rancho - Home
Django Basecamp clone
2 days, 9 hours ago # -
our top-secret code commenting project
2 days, 15 hours ago # -
Cola: Real-Time Shared Editing on Vimeo
4 days, 12 hours ago # -
If you need to pass HTTP Authorization headers through mod_wsgi, make sure you've turned WSGIPassAuthorization On http://tinyurl.com/6q2w98
5 days, 9 hours ago # -
@evilrob Have you looked at http://www.review-board.org/? Both complete and killer.
5 days, 10 hours ago # -
Jannis Leidel - An autocomplete form widget for ForeignKey model fields
5 days, 14 hours ago # -
Playing with GitPython
5 days, 14 hours ago # -
@robhudson been down that road before, strongly recommend swfobject
6 days, 13 hours ago # -
Time to upgrade lincolnloop.com to Django 1.0. Before rolling my own, is there an existing multi-user blog app out there I should look at?
1 week ago # -
Ditz
distributed bugtracking for DVCS
1 week, 4 days ago # -
git cherry-pick is my new best friend
1 week, 5 days ago # -
@howiworkdaily working on django/unfuddle api app right now. Started as a simple handle for repository callbacks, but is becoming more.
1 week, 5 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.