Wednesday, February 11, 2015

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.

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.

Overview

When creating a website or web application you will most likely need to serve the user 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 of 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 us 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. In Django we could potentially be using numerous different applications from various sources. Each of these applications might use 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 to the user. This is done by 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 a 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.
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 make use of to serve our application or site during development.
The problem is we need to specifically tell the development web server to server our static and media files. To do this we need to add some routes to our urls.py:
from django.conf import settings
if settings.DEBUG:
    urlpatterns += patterns('',
        url(r'^media/(?P.*)$', 'django.views.static.serve', {
            'document_root': settings.MEDIA_ROOT,
        }),
        url(r'^static/(?P.*)$', 'django.views.static.serve', {
            'document_root': settings.STATIC_ROOT,
        }),
)
You can see that we are telling Django to take any requests for files from our MEDIA_URL and STATIC_URL, look for them in MEDIA_ROOT and STATIC_ROOT and serve them.

django-filebrowser and grapelli

django-grappelli provides a revamp of the existing django admin look-and-feel. In itself, it simply makes your site look better – you’ll need this in case a site also needs to provide admin access to the product owner. For this case, however, we’re using grappelli as a dependency for django-filebrowser.
django-filebrowser does exactly what its name says. In a nutshell, django-filebrowser lets you navigate through and manipulate your media files through your django admin site. This is useful should you eventually need the end-user to be able to control image files without having to dig deep into the server’s internal filesystem.
First, make sure the dependencies are installed. PIL may prove tricky to install, but from there it’s all simple.
  • pip install django==1.2
  • pip install PIL==1.1.7
  • pip install django-grappelli=2.1
  • pip install django-filebrowser==3.1
You’ll be able to follow these steps, except for the ‘collectstatic’ management command (since we’re using Django 1.2) http://django-grappelli.readthedocs.org/en/latest/quickstart.htmlAlso, I used these additional settings:
Note: the PROJECT_ROOT style makes your settings more portable, so it’s a good habit to start.
Next, we make a symbolic link to the grappelli media folder (in site-packages) from your project media folder.(In the directory defined by MEDIA_ROOT)ln —symbolic /PATH/TO/site_packages/grappelli/media grappelli
Then, make sure your installed apps has this order:
Same goes for your urls,
(In the directory defined by MEDIA_ROOT)
Indicate in additional settings using this as reference:http://code.google.com/p/django-filebrowser/wiki/Settings
Once you’re set up, check it out with the following url:/admin/filebrowser/browse/ 

No comments:

Post a Comment