Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

532 lines (396 sloc) 20.663 kb
=====================
Managing static files
=====================
Aside from the HTML generated by the server, web applications generally need
to serve additional files — such as images, JavaScript, or CSS — necessary to
render the complete web page. In Django, we refer to these files as "static
files".
Also, website users may also upload files, for example if a model has a
``FileField``. In Django, we refer to these files as "media files".
In this tutorial, we will configure Django so that it can find your static
files and generate urls for them: it is the role of
``django.contrib.staticfiles``. We will also configure Django so that it can
find and generate urls for media files.
For production, we will also configure the HTTP server to directly serve these media and static files. "Directly" means that the HTTP server will not communicate with Django at all to serve these files.
.. note::
In respect of the DRY principle, best practices and portability concerns,
we are **not** going to hard code a single absolute path or URL in this
tutorial. Instead, we will configure Django to build absolute paths and
URLs. So you won't have to change your settings when you deploy your
project source code in another path or server: it is "portable". On the
other hand, you won't have to change any Python or template code when you
change a setting: Django is designed so that you **Don't Repeat Yourself**
(aka *DRY*).
Configuration overview
======================
In this tutorial, we will configure the framework and servers to work with such
a project directory::
your_project/
your_project/
__init__.py
settings.py
urls.py
wsgi.py
static/ <-------------- edit your static files in this directory
css/
style.css <---- your project's stylesheet that you edit
js/
jquery.js <---- your project's script that you downloaded
favicon.ico <------ your project's favicon that you edit
public_root/ <--------- public document root that the HTTP server will
serve directly.
media/ <----------- user uploads (ie. FileField), handled by django
static/ <---------- cached static files for the HTTP server to
serve directly, ``django.contrib.staticfiles``
is in charge of maintaining this directory
admin/ <-------- copy of django/contrib/admin/static/admin created
by django.contrib.staticfiles
css/
style.css <- copy of your_project/static/css/style.css also
created by django.contrib.staticfiles
js/
jquery.js <- copy of your_project/static/js/jquery.js else
created by django.contrib.staticfiles
favicon.ico <-- copy of your_project/static/favicon.ico also
created by django.contrib.staticfiles
- ``your_project/static/`` is where you can add, change or remove your project
specific static files because we will make it a :setting:`STATICFILES_DIRS`.
- ``your_project/public_root/media/`` is the root for media files, Django will
store uploaded files in there because we will make it our
:setting:`MEDIA_ROOT`. **You should not add, change or remove files manually
in this directory**.
- ``your_project/public_root/static/`` is the root for static files,
``django.contrib.staticfiles`` will copy static files from
:setting:`STATICFILES_DIRS` but also from each app's ``static/`` subdirectory
(ie. from ``django/contrib/admin/static/``) in there because we
will make it our :setting:`STATIC_ROOT`. **You should not add, change or
remove files manually in this directory**.
.. warning::
In this tutorial, we will also configure the HTTP server to serve
``public_root`` as a static directory. This means that you should:
- ensure that no private file (ie. python scripts ...) ever goes in this
directory because everybody will be able to download it !
- be able to store anything you want to be served by the HTTP server in
this directory, but **don't mess with the directories managed by Django
!!** - these directories are your :setting:`STATIC_ROOT` and
:setting:`MEDIA_ROOT`.
.. note::
In this tutorial, we will refer to ``django.contrib.admin`` from time to
time. You should know that ``django.contrib.admin`` does **not have any
special treatment from ``django.contrib.staticfiles``**. This means that
anything that is valid for ``django.contrib.admin`` is valid for other
external apps and also for your own apps.
.. _staticfiles-development:
How to use project static files in development
==============================================
Ensure that `django.contrib.staticfiles` is installed
-----------------------------------------------------
Open ``your_project/your_project/settings.py`` and look for
:setting:`INSTALLED_APPS`. ``'django.contrib.staticfiles'`` should be in the
list by default.
Otherwise, add it as such:
.. code-block:: python
INSTALLED_APPS = [
# your many app list ... ie. 'django.contrib.admin' could be there
'django.contrib.staticfiles',
]
Configure `django.contrib.staticfiles` to find your project static files
------------------------------------------------------------------------
In ``your_project/your_project/settings.py``, add :setting:`STATICFILES_DIRS`:
.. code-block:: python
STATCFILES_DIRS = [
os.path.join(BASE_DIR, 'static'),
]
:setting:`STATCFILES_DIRS` settings is used by
``django.contrib.staticfiles.finders.FileSystemFinder``. A finder is a class
useable by ``django.contrib.staticfiles`` to find static files. This finder is
the most basic one, but there are others, and you can make your own too, refer
to the :doc:`the staticfiles reference </ref/contrib/staticfiles>` for details.
.. warning::
**All files in any directory of STATICFILES_DIRS will be served in public.
Every directory in this setting must be considered as a public document
root.** Make sure that private contents like python scripts are **never**
in there. If in doubt, follow the tutorial's configuration precisely.
.. note::
If you have created your project prior to Django 1.5, then you will need to
add the ``BASE_DIR`` setting to ``settings.py`` yourself. It should look
like this::
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
To check if the file system static file finder
(``django.contrib.staticfiles.finders.FileSystemFinder``) is enabled, start a
:djadmin:`shell` (``python manage.py shell``) and check
:setting:`STATICFILES_FINDERS`. It should look like this (output formated for
readability)::
$ python manage.py shell
>>> from django.conf import settings
>>> settings.STATICFILES_FINDERS
('django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder')
If it is not enabled, add to ``your_project/your_project/settings.py``:
.. code-block:: python
STATICFILES_FINDERS = [
# Enables STATICFILES_DIRS, for project static files
'django.contrib.staticfiles.finders.FileSystemFinder',
# Enables apps static files, ie. for admin/static/ files
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
]
Configure the root URL for your static files
--------------------------------------------
``django.contrib.staticfiles`` uses setting :setting:`STATIC_URL` to generate
absolute paths to static files. For example, to serve file
``your_project/static/css/style.css`` on URL
``/public_root/static/css/style.css``: just set :setting:`STATIC_URL` to
``'/public_root/static/'``.
Open ``your_project/your_project/settings.py`` and add or change ``STATIC_URL`` as such::
STATIC_URL = '/public_root/static/'
Check it with with the :djadmin:`shell` (`manage.py shell`) command. It should
look like this::
$ python manage.py shell
>>> from django.conf import settings
>>> settings.STATIC_URL
'/public_root/static/'
.. _staticfiles-in-templates:
Referring to static files in templates
--------------------------------------
In your template, enable the ``static`` templatetag by loading the
``staticfiles`` template library:
.. code-block:: django
{% load staticfiles %}
<link rel="shortcut icon" type="image/x-icon" href="{% static "favicon.ico" %}" />
<link rel="stylesheet" type="text/css" href="{% static "css/style.css" %}" />
<script type="text/javascript" src="{% static "js/jquery.js" %}"
Because we set :setting:`STATIC_URL` to ``'/public_root/static/'``:
- ``{% static "favicon.ico" %}`` will render to
``/public_root/static/favicon.ico``,
- ``{% static "css/style.css" %}`` will render to
``/public_root/static/css/style.css``,
- ``{% static "js/jquery.js" %}`` will render to
``/public_root/static/js/jquery.js``.
Maybe later you decide to serve static files from a CDN ? In that case, you
will just have to change :setting:`STATIC_URL`, and ``{% static %}`` will
render appropriately.
Make Django development server serve static files
-------------------------------------------------
Open ``your_project/your_project/settings.py``, ensure that :setting:`DEBUG` is
True::
DEBUG=True
Check it with with the :djadmin:`shell` (`manage.py shell`) command::
$ python manage.py shell
>>> from django.conf import settings
>>> settings.DEBUG
True
When :setting:`DEBUG` is ``True``, Django will serve :setting:`STATIC_URL`.
.. important::
**Django development server shouldn't be used to serve static files to the
public ("in production")**. Because Django development server is built for
comfort, it ain't built for speed - nor security ! Deployment of static
files using a serious HTTP server is covered later in this document - don't
worry about it for now.
How to use media (user-uploaded) files in development
=====================================================
Configure ``MEDIA_ROOT`` and ``MEDIA_URL``
------------------------------------------
Uploaded files are stored in :setting:`MEDIA_ROOT`. As you might already know,
only their path relative to ``MEDIA_ROOT`` are stored in the actual column for
``FileField``. So, Django will still find uploaded files after you change this
setting. But this means that Django also requires a URL for `MEDIA_ROOT` to be
configured.
Open ``your_project/your_project/settings.py``, add change or add them as
such::
MEDIA_ROOT = os.path.join(BASE_DIR, 'public_root', 'media')
MEDIA_URL = '/public_root/media/'
Ensure that the settings are right with :djadmin:`shell`::
$ python manage.py shell
>>> from django.conf import settings
>>> settings.MEDIA_ROOT
'/path/to/your_project/public_root/media/'
>>> settings.MEDIA_URL
'/public_root/media/'
With this configuration, consider such an uploaded avatar:
- its location on the file system is
``/path/to/your_project/public_root/media/avatars/user0.js``,
- its url is ``/public_root/media/avatars/user0.js``,
- behind the scenes, the value of the corresponding FileField column is
``avatars/user0.jpg``,
.. warning::
**MEDIA_ROOT should be considered as a public document root !** You should
ensure that no private file like python scripts ever gets in there. If in
doubt, just follow the tutorial precisely.
.. _staticfiles-other-directories:
Serving ``MEDIA_ROOT`` on ``MEDIA_URL`` in development
------------------------------------------------------
We are going to use a generic helper function from Django to serve
``MEDIA_ROOT`` on ``MEDIA_URL`` in development. "Generic" means that you could
use this function to serve any filesystem directory on any url: it is not only
for ``MEDIA_ROOT`` and ``MEDIA_URL``.
Open ``/path/to/your_project/your_project/urls.py``, and change it so that it
looks something like this:
.. code-block:: python
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = patterns('',
# ... the rest of your URLconf goes here ...
) + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
.. note::
This helper function will only be operational in debug mode and if
the given prefix is local (e.g. ``/static/``) and not a URL (e.g.
``http://static.example.com/``).
.. _staticfiles-production:
How to serve static files with a production HTTP server
=======================================================
Django is designed so that you configure your HTTP server to serve one static
directory on a static url, without any intermediary layer. So, every static
file found by every finder must be pre-collected in the directory that the HTTP
server will serve directly as a static directory.
- :djadmin:`collectstatic` is the command to collect static files,
- it will collect static files into: :setting:`STATIC_ROOT`,
- then all we have to do is configure the HTTP server to serve
:setting:`STATIC_ROOT` on :setting:`STATIC_URL`.
Configure ``STATIC_ROOT``
-------------------------
Create the directory ``your_project/public_root/static/``, ie.::
mkdir -p /path/to/your_project/public_root/static/
Open ``your_project/your_project/settings.py``, find or add ``STATIC_ROOT`` as
such::
STATIC_ROOT = os.path.join(BASE_DIR, 'public_root', 'static')
As usual, use :djadmin:`shell` to ensure that the setting was properly
configured::
$ python manage.py shell
>>> from django.conf import settings
>>> settings.STATIC_ROOT
'/path/to/your_project/public_root/static/'
Collect static files
--------------------
The static root must be regenerated every time you add, change or remove a
static file. This is what the :djadmin:`collectstatic` command is for. You
should run this command before every deployment.
First, run it with the ``-n`` flag, which enables "dry run mode"::
-n, --dry-run Do everything except modify the filesystem.
It should look something like this::
$ python manage.py collectstatic -n
You have requested to collect static files at the destination
location as specified in your settings.
This will overwrite existing files!
Are you sure you want to do this?
Type 'yes' to continue, or 'no' to cancel: yes
Pretending to copy '/path/to/your_project/static/css/style.css'
Pretending to copy '/path/to/your_project/static/js/jquery.js'
Pretending to copy '/path/to/your_project/static/favicon.ico'
# It will also copy admin static files if you have the admin installed
Pretending to copy '/path/django/django/contrib/admin/static/admin/css/base.css'
# [...] snip ! There are too many of them !
69 static files copied. [This output is wrong and should be fixed]
i
Now, to do it for real: without ``-n``. It should look something like this::
$ python manage.py collectstatic
You have requested to collect static files at the destination
location as specified in your settings.
This will overwrite existing files!
Are you sure you want to do this?
Type 'yes' to continue, or 'no' to cancel: yes
Copying '/path/to/your_project/static/css/style.css'
Copying '/path/to/your_project/static/js/jquery.js'
Copying '/path/to/your_project/static/favicon.ico'
# It will also copy admin static files if you have the admin installed
Copying '/path/to/django/contrib/admin/static/admin/css/dashboard.css'
# [...] snip ! There are too many of them !
69 static files copied.
The project should look like this::
your_project/
static/ <--------- editable static files
favicon.ico
css/
style.css
js/
jquery.js
public_root/ <------ public document root
media/ <------ user uploads go there
static/ <------ collectstatic just took care of this !
favicon.ico
css/
style.css
js/
jquery.js
your_project/
__init__.py
settings.py
urls.py
wsgi.py
Now, we have an up-to-date static root and all we have to do is configure the
HTTP server to serve it.
.. warning::
The HTTP server process needs to have read+execute permission on each
directory in ``STATIC_ROOT`` **and on each parent directory !!**. Also, it
should have read permission on every collected file in ``STATIC_ROOT``.
Configure the HTTP server to serve ``STATIC_ROOT`` on ``STATIC_URL``
--------------------------------------------------------------------
In these example, we will consider ``STATIC_ROOT`` to be
``/path/to/your_project/public_root/static/`` and ``STATIC_URL`` to be
``/public_root/static/``. You might be wondering why we use the ``public_root``
parent directory: it's just to allow other statically served directories and
make the configuration shorter: it is a best practice.
For Nginx HTTP server, you could add something like this in the ``server``
directive of your Django website::
location ^~ /public_root/ {
alias /path/to/your_project/public_root/;
}
On Apache, it could be like this::
Alias /public_root/ /path/to/your_project/public_root/
<Directory /path/to/your_project/public_root>
Order deny,allow
Allow from all
</Directory>
Learn more
==========
Those are the **basics**. For more details on common configuration options,
read on; for a detailed reference of the settings, commands, and other bits
included with the framework see
:doc:`the staticfiles reference </ref/contrib/staticfiles>`.
You can also write your own storage backend to handle complex storages, see
:doc:`/howto/custom-file-storage`.
The `django-storages`__ project is a 3rd party app that provides many
storage backends for many common file storage APIs (including for
`Amazon S3`__).
__ http://code.larlet.fr/django-storages/
__ http://s3.amazonaws.com/
You can also find `many apps related to asset management on
djangopackages.com`__. Some will compress your staticfiles, compile
CoffeScript, etc, etc...
__ https://www.djangopackages.com/grids/g/asset-managers/
Upgrading from pre 1.3 Django versions
======================================
In previous versions of Django, it was common to place static assets in
:setting:`MEDIA_ROOT` along with user-uploaded files, and serve them both at
:setting:`MEDIA_URL`. Part of the purpose of introducing the ``staticfiles``
app is to make it easier to keep static files separate from user-uploaded
files.
For this reason, you need to make your :setting:`MEDIA_ROOT` and
:setting:`MEDIA_URL` different from your :setting:`STATIC_ROOT` and
:setting:`STATIC_URL`. You will need to arrange for serving of files in
:setting:`MEDIA_ROOT` yourself; ``staticfiles`` does not deal with
user-uploaded files at all. You can, however, use
:func:`django.views.static.serve` view for serving :setting:`MEDIA_ROOT` in
development; see :ref:`staticfiles-other-directories`.
Upgrading from ``django-staticfiles``
=====================================
``django.contrib.staticfiles`` began its life as `django-staticfiles`_. If
you're upgrading from `django-staticfiles`_ older than 1.0 (e.g. 0.3.4) to
``django.contrib.staticfiles``, you'll need to make a few changes:
* Application files should now live in a ``static`` directory in each app
(`django-staticfiles`_ used the name ``media``, which was slightly
confusing).
* The management commands ``build_static`` and ``resolve_static`` are now
called :djadmin:`collectstatic` and :djadmin:`findstatic`.
* The settings ``STATICFILES_PREPEND_LABEL_APPS``,
``STATICFILES_MEDIA_DIRNAMES`` and ``STATICFILES_EXCLUDED_APPS`` were
removed.
* The setting ``STATICFILES_RESOLVERS`` was removed, and replaced by the
new :setting:`STATICFILES_FINDERS`.
* The default for :setting:`STATICFILES_STORAGE` was renamed from
``staticfiles.storage.StaticFileStorage`` to
``staticfiles.storage.StaticFilesStorage``
* If using :ref:`runserver<staticfiles-runserver>` for local development
(and the :setting:`DEBUG` setting is ``True``), you no longer need to add
anything to your URLconf for serving static files in development.
Jump to Line
Something went wrong with that request. Please try again.