Managing static media urls

8 views
Skip to first unread message

Greg

unread,
Jan 14, 2006, 2:53:24 AM1/14/06
to Django users
Andy Shaw posed an interesting question in the topic "CSS and PNG files
in templates" (in this discussion group)... what kind of URL do you put
in a template when you want to refer to a static file? If you use URLs
that encode too much information (like a hostname or an absolute path),
then it becomes a PITA to move the app to another host, or to rearrange
your folder structure. This issue seems especially pertinent for Django
because although the mechanism for assembling several apps together on
one server is a sweet way to make it easy to combine and reconfigure
applications, having to specify a single global MEDIA_ROOT/MEDIA_URL
kind of limits it. You can't just put static files in the same
directory as the template files, like JSP developers (for instance)
often do. It'd be convenient if each app had "media" subdirectory or
something to go with its models, views, and templates. And actually,
the admin app is an excellent example of this! But admin has to have
its own special setting (ADMIN_MEDIA_PREFIX) and handler to make it
work. Is there any suggested strategy for how other apps can have their
own media directories too? What's the common practice?

Amit Upadhyay

unread,
Jan 14, 2006, 3:14:30 AM1/14/06
to django...@googlegroups.com
On 1/14/06, Greg <goo...@abbas.org> wrote:

your folder structure. This issue seems especially pertinent for Django
because although the mechanism for assembling several apps together on
one server is a sweet way to make it easy to combine and reconfigure
applications, having to specify a single global MEDIA_ROOT/MEDIA_URL
kind of limits it. You can't just put static files in the same
directory as the template files, like JSP developers (for instance)
often do. It'd be convenient if each app had "media" subdirectory or
something to go with its models, views, and templates. And actually,
the admin app is an excellent example of this! But admin has to have
its own special setting (ADMIN_MEDIA_PREFIX) and handler to make it
work. Is there any suggested strategy for how other apps can have their
own media directories too? What's the common practice?

 Static files are best served by basic http servers and not django. Django tries to support serving static files, but that is only for convenience in development. Just now I finished deploying a django project under mod_pythong/apache, and my approach was to setup a /static url pointing to a directory containing static files and I setup django's static file serving view for that, I did that till the development lasted, and then I moved it to apache, and put a:
<Location "static">
     SetHandler None
</Location>
like directive in apache conf to bypass django for them. I have setup apache to server / using django. /static contained directores for different application, modified ADMIN_MEDIA_PREFIX to point to this location, and developed my other application assuming my static files will be available at /static/myapp/.

The only thing I am missing in this approach is: my 404 views are not called when some file is unavailable, and ugly looking apache default comes up. I can change apache's 404 page to someother, but it seems it has to be static html file, not explored it much, but then its not really too bad.

--
Amit Upadhyay
Blog: http://www.rootshell.be/~upadhyay
+91-9867-359-701

Andy Shaw

unread,
Jan 14, 2006, 8:33:53 AM1/14/06
to django...@googlegroups.com
Amit Upadhyay wrote:
> Static files are best served by basic http servers and not django.
> Django tries to support serving static files, but that is only for
> convenience in development. Just now I finished deploying a django
> project under mod_pythong/apache, and my approach was to setup a /static
> url pointing to a directory containing static files and I setup django's
> static file serving view for that, I did that till the development
> lasted, and then I moved it to apache, and put a:
>
> <Location "static">
> SetHandler None
> </Location>
>

This is the exact approach that I use, but it doesn't avoid the issue
that Greg is talking about. That is; a series of static-file URLs are
likely to be associated with any given application, and the path to them
isn't necessarily going to be the same for each installation of that
application (because, amongst other reasons, there are many different
ways they could be deployed - as you've just shown).

Personally, I'm happy using root-relative URLs for the moment. The
resulting directory structure isn't overly complicated, so could be
easily replicated. However, I can think of a couple of approaches to
ease the problem:

1) Make it a standards that your apps will have all their media in
/static/appname/. This isn't hard to do, and produces an easily portable
directory tree. Root-relative (or absolute) again, though.

2) Create all your templates so that static media urls look like
"{{base_url}}/image.png". Define a constant at the top of the file
defining your views, and store the appropriate base URL in it. Pass this
constant into your template renderer. This means that where you are
storing your static files is only hardcoded once, and can easily be changed.

In fact, I think I've seen a couple of people write function decorators
and other nifty tricks specifically to do things like render templates
with additional variables... just a thought.

The problem with both of these approaches is that if you're
using an app (or several) that you haven't written yourself, they won't
necessarily follow this standard, and could conflict.

-Andy

Greg

unread,
Jan 14, 2006, 11:17:42 PM1/14/06
to Django users
Thanks for the advice guys. Amit, yeah I should have mentioned that I
totally agree that django shouldn't serve static files in a production
environment. And keeping a /static/ directory sounds like a pretty good
way to do that.

I started writing something more like Andy's #2 suggestion... a way to
abstract the media root so it doesn't have to be hardcoded all over my
templates. I made a tag to generate static URLs, and hacked the django
code in order to remember a template's application's settings like the
location of the media directory (if the template belongs to a
application, that is). It works really well but I imagine there are
various kinds of issues to consider for a facility like that. And
you're right Andy, it's not really a ideal solution unless all the apps
you're using use it. Well, it sounds like the dev team has their hands
full right now with more important things like magic-removal and 1.0,
but maybe I'll float this idea after that. Mostly I just wanted to make
sure I wasn't high or completely missing the point.

Afternoon

unread,
Jan 17, 2006, 12:13:29 PM1/17/06
to django...@googlegroups.com

I'd like to have a solution to this problem too.

My specific problem is that I have a bunch of sites in development on
my laptop:

http://localhost/coolsite/
http://localhost/boringsite/
http://localhost/newhomepage/

And these then get deployed to production servers:

http://coolsite.com/
http://boringsite/newcoolthing/
http://homepage.org/

I solve it right now by adding a setting, URLBASE, and then doing
circles to get it into everything, mainly with lots of extra_context
stuff to push it through generic views into templates.

I'm aware this is sub-optimal.

One solution is to use the sites functionality - will Django bork if
my site url is localhost/folder?

The other is to use a middleware or context processor to pull in
URLBASE.

Ben


________________________________
Afternoon, man about the Internet -- http://aftnn.org/


dere...@gmail.com

unread,
Jan 17, 2006, 8:27:37 PM1/17/06
to Django users
I think there are a few ways of doing this in previous messages, but
here's what has worked for me, using a custom context processor.

In settings, I add whatever custom variables I want, including this:
APP_BASE = "http://www.example.com/"

I have an app called home, and in the views.py I put this:
---
"""
A request processor that returns dictionary to be merged into a
template context. Function takes the request object as its only
parameter
and returns a dictionary to add to the context.

These are referenced from the setting TEMPLATE_CONTEXT_PROCESSORS and
used by DjangoContext.
"""

from django.conf.settings import APP_BASE

def set_vars(request):
"""
Returns custom context variables required by this app from
settings.py
"""
context_extras = {}
context_extras['APP_BASE'] = APP_BASE
return context_extras

---------
You could add other custom variables to this.

In settings again, I added to...

TEMPLATE_CONTEXT_PROCESSORS = (
...
"django.models.home.set_vars",
)

In the template use
<a href="{{ APP_BASE }}thing/somethingelse/">...

The one gotcha with this is you must remember to use DjangoContext in
your views:
from django.core.extensions import DjangoContext as Context

But then you have to do that to use any of the template context
processors.

Derek

Nebojša Đorđević

unread,
Jan 19, 2006, 2:05:38 PM1/19/06
to django...@googlegroups.com
Afternoon wrote:
>
>
> I'd like to have a solution to this problem too.
>
> My specific problem is that I have a bunch of sites in development on my
> laptop:
>
> http://localhost/coolsite/
> http://localhost/boringsite/
> http://localhost/newhomepage/
>
> And these then get deployed to production servers:
>
> http://coolsite.com/
> http://boringsite/newcoolthing/
> http://homepage.org/
>

Well, if all of your sites are separate django projects that's easy, you already have a (static) dir pointed by your
MEDIA_URL, so:

1. Store file system path to your project in the SITE_ROOT variable in the config file.

2. Anywhere when you must supply a path (like ImageField, MEDIA_ROOT, etc.), use os.path.join(SITE_ROOT, 'foo').

3. Put all of your static files under /media/ and always use URLs like this /media/img/foo.png, /media/js/foo.js, etc.

4. Setup URLs:
- Config file:
ADMIN_MEDIA_PREFIX = '/admin-media/'
MEDIA_URL = os.path.join(SITE_ROOT, 'media')
MEDIA_PREFIX = '/media/'

- Apache:
Alias /media/ "<SITE_ROOT>/media/"
Alias /admin-media/ "<django root>/django/contrib/admin/media/"

- Lighttpd:
alias.url = (
"/media/" => "<SITE_ROOT>/media/",
"/admin-media/" => "<django root>/django/contrib/admin/media/",
)


5. Also you can use this in your main url conf to make this files accessible when using django-admin.py runserver (from
another post on the list) - admin media files are handled automagically:

from django.conf.settings import LOCAL_DEV, SITE_ROOT
if LOCAL_DEV:
import os
urlpatterns += patterns('',
(r'^media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': os.path.join(SITE_ROOT, 'media')}),
)
#

I'm using a LOCAL_DEV var to distinguish between local runserver (DEBUG=LOCAL_DEV=True), staging server (DEBUG=True,
LOCAL_DEV=False) and production server (DEBUG=LOCAL_DEV=False).

With this setting I have a local server, a staging server and a production server setup which only differs in SITE_ROOT
(sometimes, because I tend to replicate directory structure from my production server), LOCAL_DEV and DEBUG variables.

--
Nebojša Đorđević - nesh
Studio Quattro - Niš - SCG
http://studioquattro.biz/forum/

http://djnesh.blogspot.com/ | http://djnesh-django.blogspot.com/ |
http://djangoutils.python-hosting.com/
Registered Linux User 282159 [http://counter.li.org]

Afternoon

unread,
Jan 20, 2006, 8:21:59 AM1/20/06
to django...@googlegroups.com

I'm not just using this for media (despite the subject line!). I also
the URLBASE for building absolute urls in models and in templates.
MEDIA_URL generally ends up as something like:

MEDIA_URL = URLBASE + "/media/"

Something like Rails' routing would be really interesting for me, but
I confess I don't really know much about their solution, or what
would be a good fit here.

On 19 Jan 2006, at 19:05, Nebojša Đorđević wrote:

> Well, if all of your sites are separate django projects that's
> easy, you already have a (static) dir pointed by your
> MEDIA_URL, so:

Nebojša Đorđević

unread,
Jan 20, 2006, 11:41:29 AM1/20/06
to django...@googlegroups.com
Afternoon wrote:
>
>
> I'm not just using this for media (despite the subject line!). I also
> the URLBASE for building absolute urls in models and in templates.
> MEDIA_URL generally ends up as something like:
>
> MEDIA_URL = URLBASE + "/media/"
>

Yes, I also hit the same problem, but because I have control of my DNS, I use sub domains for stuff like that. So
http://boringsite/newcoolthing/ becomes http://newcoolthing.boringsite/.

Kevin

unread,
Jan 20, 2006, 1:45:24 PM1/20/06
to Django users
I think the question at hand is not where to store and serve the media
files, but how to write an app that can easily support accessing media
files from different urls. I had this same issue between my
development and production apache servers:

Dev Site
localhost/mysite/images/whatever.gif

Production
mysite.com/images/whatever.gif

And even the occasional development on my laptop on the road
localhost/~myuser/mysite/images/whatever.gif

This was never a problem in my previous dev environment (php) because
I'd always just use relative urls like:

<img src="images/whatever.gif">

But with django's more flexible url mapping, I need to make all the
links absolute.

The most frequent suggestion is just to define a setting such as the
MEDIA_ROOT that can be set to "/images" on my production server,
"/mysite/images" on my dev and then "~myuser/mysite/images" on the
laptop example.

Looking at ruby on rails, they seem to have some template tag
equivalent that does url generation for you automatically (stolen from
the rails tutorial):
<%= link_to recipe.title.....

Perhaps django could use something similar?

Reply all
Reply to author
Forward
0 new messages