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.
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.
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
MEDIA_ROOTthis is the absolute path to the folder that will hold our user uploads. For example
MEDIA_ROOT = "/User/Timmy/Sites/Pho/root/media/".
MEDIA_URLthis is the relative browser URL to be used when accessing our media files in the browser. For example
MEDIA_URL = "media/"
STATIC_ROOTthis is the absolute path to the folder within which we want our static files to be collected by the
staticfilesapplication. For example
STATIC_ROOT = "/User/Timmy/Sites/Pho/root/static/"
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/"
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.
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
MEDIA_URL and return the files immediately from the
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.
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.
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)
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