Michael Trier has a blog post on how he keeps his Django projects portable from one directory to another. This is something that gave us a hard time at work too and that we managed to fix (differently.)
To give you a brief idea of what we do, we usually develop small web sites for small companies. Because of the pains of using PHP, we moved all our new development to Django and have been satisfied. There are some areas that have caused us trouble however, and the number one pain is deployment. Some things are out of our hands, such as restarting Apache when a Python file is modified. But having to change a bunch of directories and URLs whenever we deployed, that was way too annoying not to be fixed.
We have a basic Django project skeleton that we now use whenever we start a new site. It is called WSF (short for “WebSite Framework”.) Before we had WSF, we started ever new project with the startproject command, and did everything anew over and over. The really sucky part was that between my designer and me, code would sometimes break because we did not keep our working copy in directories with the same names. And with the demos and the production servers having different directory names, it was evident that we needed to do something about that.
Our web sites usually go through four different file system paths:
- My working copy
- The working copy of my designer
- Our demo server
- The production server
We also needed our projects to work with different base URLs:
- Development URLs (directly at the root)
- Demo URLs (under /demos/client/wsf/)
- Production URLs (under /wsf/ for technical reasons)
Paths
The first problem we concentrated on were the file system paths. Because the settings file in Django is a Python script, it was possible to use the path manipulation libraries to achieve portability. There are two paths you want to set in the settings.py module: MEDIA_ROOT and TEMPLATE_DIRS.
By using os.path, it was possible to set the correct paths dynamically:
PROJECT_PATH = os.path.dirname(os.path.abspath(__file__))
MEDIA_ROOT = os.path.join(PROJECT_PATH, 'media')
TEMPLATE_DIRS = (
os.path.join(PROJECT_PATH, 'templates'),
)
The magic __file__ variable is the name of current module, in this case, settings.py. We use abspath to get the complete path, and we truncate the file name with dirname. This fixed all our path related problems, it was now easy to move the application between different folders.
URLs
Our next problem were the URLs. When we developed on our own machine with the built-in development server, the URLs were simply http://server:9090/foo/. When we moved the project to the demo server (served by Apache), the base URL was http://demoserver/demos/client-domain.com/wsf/. The reason for the trailing /wsf/ is that all of our projects have the name wsf, so for the import statement to work in Python, the folder needs to be named wsf too. We use .htaccess files to tell Apache to server the directory as a Django application.
We fixed the changing URL problem by defining a variable in the settings file called BASE_URL. In development mode, this would be set to the empty string, and on the demo server, we’d change it to ‘demos/client-domain.com/wsf/’.
Our urls.py file used this setting:
from django.conf.urls.defaults import *
from django.conf import settings
urlpatterns = patterns(
'',
(r'^%s' % settings.BASE_URL, include('wsf.site.urls')),
)
And in the site/urls.py file, the URLs were defined normally. By using the {% url %} tag in the templates and the reverse() function in the Python code, our URLs were portable…
But not all of them. There was no way to use {% url %} with the media files. We fixed this problem with a filter:
from django.conf import settings
@register.filter
def media(file):
'''
Concatenate MEDIA_URL and file.
'''
return settings.BASE_URL + file
So whenever we need to display a media file, we do the following:
<img src="{{ "images/foo.jpg"|media }}" />
and the correct URL will be used. We also use this filter in our CSS files (they are not served statically) for when we use the url() command.
Conclusion
With these simple settings, when we move an application from development to the demo or the production server, we need only change the BASE_URL setting and the rest of the project will work as expected.
I would say that this whole path and URL thing needs to have a better engineered solution before 1.0 is released. With PHP, it’s extremely easy to move an application from one server to another, and restarting the server is not necessary whenever a .php file is modified. The Django hackers really need to get together and figure a way to make this easier, because it’s really hard to sell the rest of the framework if putting an application online is so painful.
Posted by gnuvince
Posted by gnuvince
Posted by gnuvince