Login

Serve static media files from app/media subdirectory

Author:
adamlofts
Posted:
August 5, 2008
Language:
Python
Version:
.96
Score:
2 (after 2 ratings)

This view will serve media files from all media subdirectories of apps in your INSTALLED_APPS setting. Save the view as media.py in your django site folder and add to urls.py:

if settings.DEBUG:
    urlpatterns += patterns('',
        (r'^media/(?P<appname>\w+)/(?P<path>.+)$', 'devel_site.media.serve_apps')
    )`

Now suppose your installed apps setting looks like: INSTALLED_APPS = ('org.myself.myapp', ...)

Then a request to http://localhost/media/myapp/directory/file.css will serve the file org/myself/myapp/media/directory/file.css.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import os
import mimetypes
from django.conf import settings
from django.shortcuts import Http404
from django.http import HttpResponse

def serve_apps(request, appname, path):
    """
    Serve static files from media folders in all installed apps

    To use put a URL pattern such as:
        (r'^media/(?P<appname>\w+)/(?P<path>.+)$', 'media.serve_apps')

    Then the media in my_installed_app/media will be available at the url media/my_installed_app

    This view is intended for development purposes only and you should properly configure your
    webserver to serve media in production use.
    """
    for app in settings.INSTALLED_APPS:
        # Split of the last part of the app name; e.g. 'django.contrib.admin' -> 'admin'
        app_short_name = app.rpartition('.')[2]
        if app_short_name == appname:
            # Work out the directory in which this module resides
            mod = __import__(app)
            moddir = os.path.dirname(mod.__file__)
            
            abspath = os.path.join(moddir, 'media', path)
            if not os.path.exists(abspath):
                raise Http404("Could not find media '%s' for app '%s' at location '%s'" % (path, appname, abspath))
            if not os.path.isfile(abspath):
                raise Http404("Media '%s' at '%s' is not a file" % (path, abspath))
            
            # Return the file as a response guessing the mimetype
            mimetype = mimetypes.guess_type(abspath)[0] or 'application/octet-stream'
            contents = open(abspath, 'rb').read()
            response = HttpResponse(contents, mimetype=mimetype)
            response["Content-Length"] = len(contents)
            return response

    raise Http404("Could not find app of name '%s'" % (appname,))

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 10 months, 2 weeks ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 3 weeks ago
  3. Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
  5. Help text hyperlinks by sa2812 1 year, 6 months ago

Comments

phxx (on August 5, 2008):

A good Idea, but i think serving media files should be the job of an apache webserver or lighttpd or something similar. It would me more usefull to make the media directory in every app a good practice and then to make symbolic links in your real media directory.

#

carljm (on August 5, 2008):

phxx: Um, the suggested usage clearly indicates this is for development use, not production.

This is a great idea. It liberates me from making all those symlinks, which become a huge pain when multiple developers are working on the same project on different systems with different path setups. +1 from me, wish I'd thought of it!

#

phxx (on August 5, 2008):

Oh right. I've overseen the if settings.DEBUG.

#

carljm (on August 5, 2008):

I also have project-wide media in MEDIA_ROOT that I'd like to have served at media/. I just removed the final line (raise Http404...) and replaced it with this:

# if app not found, fall back to regular static serve from MEDIA_ROOT
full_path = "%s/%s" % (appname, path)
return serve(request, path=full_path, document_root=settings.MEDIA_ROOT)

And added this near the top:

from django.views.static import serve

#

carljm (on August 14, 2008):

One other note - this code is Python 2.5 specific as written. It can easily be made compatible with previous versions by replacing this line:

app_short_name = app.rpartition('.')[2]

with:

app_short_name = app.rsplit('.', 1)[-1]

#

Please login first before commenting.