Django static media always returning 404 not found

6 October 2010

I spent too long tonight figuring out a weird problem.

On a dev server, I was using django.views.static.serve to serve media files. But it was returning 404 (not found) for any file.

The requests for media files weren’t even showing up in Django’s built-in server’s output. That had me baffled until I dug deep enough in Django’s code to figure it out.

The ADMIN_MEDIA_PREFIX was the same as MEDIA_URL. That was it.

Django’s built-in server doesn’t log requests for admin media, so that’s why there was no log output.

The built-in server also handles admin media separately, so when I tried to request a media file, it intercepted and looked for it in the admin media.

The solution is for the ADMIN_MEDIA_PREFIX to be different from MEDIA_URL, e.g. /media/ and /media/admin/.

Filed under: Django — Scott @ 10:19 pm


  1. It’s not your fault. By default, Django puts the following in for a new site:

    # URL that handles the media served from MEDIA_ROOT. Make sure to use a
    # trailing slash if there is a path component (optional in other cases).
    # Examples: “”, “”
    MEDIA_URL = ”

    # URL prefix for admin media — CSS, JavaScript and images. Make sure to use a
    # trailing slash.
    # Examples: “”, “/media/”.
    ADMIN_MEDIA_PREFIX = ‘/media/’

    One of my biggest Django peeves is the built-in confusion over the right way to serve static media and refer to it in templates. The default source code above strongly implies doing it one (confusing) way, while the docs ( suggest something completely different (setting up a STATIC_DOC_ROOT variable).

    Comment by Brent Tubbs — 7 October 2010 @ 3:29 am

  2. Ah, if I’d read the docs I might have seen this warning:

    “Be careful not to use the same path as your ADMIN_MEDIA_PREFIX (which defaults to /media/) as this will overwrite your URLconf entry.”

    Comment by Scott — 7 October 2010 @ 9:15 am

  3. The term “media” always struck me as a poor choice, as it means both everything and nothing and is guaranteed to confuse a Django newcomer (as it once did confuse me). Which is why my Django deployments are set up with what I consider less confusing terminology:

    /upload – the stuff that users uploaded to the server, i.e. what Django refers to as media (served under MEDIA_URL and stored in MEDIA_ROOT on the filesystem).
    /static – the static part of my project/site, such as icons, Javascript files, CSS, etc. (I keep this well separate from /upload, as it is truly static and lives in version control, unlike /upload)
    /adminmedia – the static parts of Django’s admin interface, which is served under ADMIN_MEDIA_PREFIX and part of Django. Arguably this should live under /static/admin, but I prefer the clean separation in case I need to more one or the other to a separate host for whatever reason (performance, CDN, …)

    Hopefully if Django ever decides to make some rather backwards-incompatible changes, this gets cleaned up :-)

    Comment by Ingmar — 8 October 2010 @ 5:03 pm

  4. I’ve been struggling with *exactly* the same problem. Thanks for posting!

    Comment by David Talbot — 21 November 2010 @ 11:00 am

  5. wow very helpful, I hadn’t changed me admin-media url and was comparing my settings file between two django apps trying to figure out why the static server was returning 404. By default a django settings project should set them differently to avoid this problem.

    Comment by morgan — 14 February 2011 @ 1:45 am

  6. You are a star! Thanks mate :)

    Comment by Glyn Mooney — 14 April 2011 @ 10:07 am

RSS feed for comments on this post.

Leave a comment