Friday, May 9, 2008

Unable to define my urls exactly my way (resignation statement)

I've been working with Django for a while, and it helped me to get all my web developments with nice urls. But I also wanted a nice url structure...

What it is nice for me, opposite to Django default settings, is avoiding the media prefix on my media urls, so

http://localhost/media/admin/css/login.css would be http://localhost/admin/css/login.cssTrying to emulate old website structures (used widely in php sites).

That could be nice or not, but for sure it is complicated.

The first step was to setup apache for it, a little bit more complicated than the usual setup, but possible:

<LocationMatch "/((css|js|img|swf|pdf)/|favicon.ico)">
SetHandler None

The main problem comes when using Django development http server (started by "python runserver"), and the admin. Of course you can do that, but what is not possible, is to define the same name for your admin media path, and for the admin itself.

For example:

http://localhost/admin and http://localhost/admin/css/login.css

The reason is the Django web server, processes all requests starting with the ADMIN_MEDIA_PREFIX setting with the AdminMediaHandler, what implies with that structure that all admin requests (even the ones that aren't static files) are processed by this handler, raising an error when the request isn't for a static file. The error is next.

Permission denied: ${PYTHON_PATH}/django/contrib/admin/media/

So this is my resignation statement to do what I wanted to do initially. Now, options are:

  • Don't use the Django http server (use apache even for development)

  • Keep the same structure but change the admin media directory (for example from "admin" to "admin-media"

  • Use the "media" (or any other name) prefix

NOTE: Current version of my project DSNP is affected by this issue. I'll solve it asap.


  1. Did you try to write a custom MIDDLEWARE to serve admin media? Placed instead of AdminMediaHandler would do the job (It could be just a copy of AdminMediaHandler which whould "ignore" the request if it's not for an existing file).

    Just my 0.02

    See you!

  2. Thank you for the idea, but there are a couple of things that I don't like on it.

    The first is that I don't want to create a middleware and change my application in production with something that will be useful just for development (I know that I can create a conditional checking if DEBUG is True, but anyway I don't like it).

    The second thing is that it's difficult to know when to serve a static file or a generated page in a reliable way (unless it, I would create a ticket to solve it inside Django). I can check by extension, by path, or try a url on if the file isn't found on the filesystem , but it's not enough reliable for me (for latter case, may be the request is for a static file that doesn't exist).

    What made me resign on that model, is that there is no perfect way to approach it since it could be a path that is at the same time a static file, and a url at Not usual, but this must be avoid on the basis.

  3. I usually re-program my admin media to be at /admin/media instead of the default /media as I would rather use /media for my own site media, this gives me the sub-folders "/media/images", "/media/css", "media/js", etc.

    When replacing an older PHP site, I would only go for backwards compatibility to a certain point. I don't really see an issue with having to access images using "/media/images/imagename.jpg", etc. in fact I prefer them all in a separate folder anyway, at least if I get somebody to FTP into a production server to upload an image, I can tell them to leave all other folders but the media folder alone.

    Also that way, I can continue using the built in web server that comes with Django. I use this feature a lot, especially since discovering "Instant Django", which now allows me to carry a fully working copy of my websites, using SQLite database on a USB stick. This has been invaluable for quickly showcasing websites that are still under construction, or even working off site, but it would make it a lot more awkward to do, if I also had to carry Apache or Lighttpd on the USB stick.

  4. I have an easy way that keeps my static content in my SVN repository, serves the static content locally when I'm running the development server and uses Apache when deployed.

    1. Create a folder for your static content. I call mine 'static'. Put it in your project folder.
    2. in the default urls for the project add this:
    # On the production server, add these lines to the site config
    # so this doesn't get used except on development boxes:
    #Alias /static "/home/projectname/static"
    # SetHandler None
    {'document_root': settings.MEDIA_ROOT}
    3. As it says in the comment, add the config to the apache server.
    4. settings:
    MEDIA_ROOT = os.path.join(SETTINGS_FILE_FOLDER, 'static')
    MEDIA_URL = '/static/'
    ADMIN_MEDIA_PREFIX = '/media/'

    This setup works great for me and is very flexible.