Understanding, setting up, accessing and serving media files and static files in Django

One of my most popular Stackoverflow answers is to a question regarding the confusion between static and media files in Django. This post elaborates on that theme.

👋 Hello Stackoverflow

My most popular answer on Stackoverflow is from a question that arose from the confusion between media & static files in Django. As it remains popular and is still receiving upvotes, I thought I would write it up as a full blog post.

When creating a website or web application you will most likely need to serve files; images, downloads, css stylesheets, javascript files etc.

These files can be partitioned into two families:

  • those files used in the development, creation and rendering of the website or app. Things like stylesheets, scripts, fonts etc. In Django, these are our static files
  • those files that are uploaded during the normal usage of the website or application such as images, pdfs, videos etc. In Django, these are our media files

Dealing with media files is straightforward in Django. Django simply expects us to tell it where in the file system we want to keep and upload our media files as well as the URL under which we would like access to them when serving our website.

Our static files are a little bit more complicated. We could potentially be using a number of different Django applications from various sources. Each of these Django applications might have their own static files to render any widgets or interfaces they might supply.

We therefore need to be able to collect all of those scattered resources and tell Django to put them in one place so that we can serve them all to the user. This is done using the built-in static files app in django.contrib.staticfiles. You should read through the documentation as it’s outside the scope of this post, but briefly, Django provides a command to search and collect any static files throughout your project: python manage.py collectstatic. This will gather all of the distributed static files into one single location that can be easily served.

Setup

To get our static and media files up and running for our project, there are a number of variables we need to set in our project’s settings.py:

  • MEDIA_ROOT this is the absolute path to the folder that will hold our user uploads. For example MEDIA_ROOT = "/User/Timmy/Sites/Pho/root/media/".
  • MEDIA_URL this is the relative browser URL to be used when accessing our media files in the browser. For example MEDIA_URL = "media/"
  • STATIC_ROOT this is the absolute path to the folder within which we want our static files to be collected by the staticfiles application. For example STATIC_ROOT = "/User/Timmy/Sites/Pho/root/static/"
  • STATIC_URL like MEDIA_URL, this variable is the relative browser URL to be used when accessing our media files in the browser. For example STATIC_URL = "static/"

Tip

Don’t manually set the absolute paths for your static and media folders. Instead, you can do the following:

ENV_PATH = os.path.abspath(os.path.dirname(__file__))
MEDIA_ROOT = os.path.join(ENV_PATH, 'media/')

This will automatically detect the absolute path to the settings.py file and then append media/ to it given you a dynamically generated path to your media root.

Deployment & Serving

Now that we have told where Django can find our various files as well as the URLs they can be located under, we need to actually serve the files for incoming requests. Generally there are two possible scenarios; a production or development environment.

When a user requests a static or media file in a production environment, we want our web server (nginx/apache etc.) to deal with the request and return the file instead of passing the request down to the application server (uwsgi/gunicorn etc.). To do this we need to configure our webserver to listen for requests that match our STATIC_URL and MEDIA_URL and return the files immediately from the STATIC_ROOT and MEDIA_ROOT folders. How we go about configuring this is outside the scope of this post, but there is an example for NGINX on Stackoverflow as well as Apache.

On the other hand, when working in a development environment, we don’t want to go through the complications of having to set up and configure a fully fledged web server. Thankfully Django provide a very basic web server application that we can use to server our application during development. We can also server our static and media files through this development server too.

Static files in development

For our static files, it’s very easy. Since Django 1.9, we don’t need to do anything extra to serve our static files in development. We just need to make sure the django.contrib.staticfiles app is added to our INSTALLED_APP (which is the case by default). The runserver command will automatically take care of the rest.

Media files in development

For our media files, we do need to make a small change to have our user-uploaded files served during development. In your main urls.py you can add the following:

from django.conf import settings
from django.conf.urls.static import static
 
urlpatterns = [
    # ... the rest of your URLconf goes here ...
]
 
if settings.DEBUG is True:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Conclusion

So, you now have a basic understanding of the differences between the two. Next, have a read of the more detailed Django documentation on static files as well as the documentation for uploading files to your MEDIA_ROOT