123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565 |
- =======================
- The ``staticfiles`` app
- =======================
- .. module:: django.contrib.staticfiles
- :synopsis: An app for handling static files.
- ``django.contrib.staticfiles`` collects static files from each of your
- applications (and any other places you specify) into a single location that
- can easily be served in production.
- .. seealso::
- For an introduction to the static files app and some usage examples, see
- :doc:`/howto/static-files/index`. For guidelines on deploying static files,
- see :doc:`/howto/static-files/deployment`.
- .. _staticfiles-settings:
- Settings
- ========
- See :ref:`staticfiles settings <settings-staticfiles>` for details on the
- following settings:
- * :setting:`STORAGES`
- * :setting:`STATIC_ROOT`
- * :setting:`STATIC_URL`
- * :setting:`STATICFILES_DIRS`
- * :setting:`STATICFILES_FINDERS`
- Management Commands
- ===================
- ``django.contrib.staticfiles`` exposes three management commands.
- ``collectstatic``
- -----------------
- .. django-admin:: collectstatic
- Collects the static files into :setting:`STATIC_ROOT`.
- Duplicate file names are by default resolved in a similar way to how template
- resolution works: the file that is first found in one of the specified
- locations will be used. If you're confused, the :djadmin:`findstatic` command
- can help show you which files are found.
- On subsequent ``collectstatic`` runs (if ``STATIC_ROOT`` isn't empty), files
- are copied only if they have a modified timestamp greater than the timestamp of
- the file in ``STATIC_ROOT``. Therefore if you remove an application from
- :setting:`INSTALLED_APPS`, it's a good idea to use the :option:`collectstatic
- --clear` option in order to remove stale static files.
- Files are searched by using the :setting:`enabled finders
- <STATICFILES_FINDERS>`. The default is to look in all locations defined in
- :setting:`STATICFILES_DIRS` and in the ``'static'`` directory of apps
- specified by the :setting:`INSTALLED_APPS` setting.
- The :djadmin:`collectstatic` management command calls the
- :meth:`~django.contrib.staticfiles.storage.StaticFilesStorage.post_process`
- method of the ``staticfiles`` storage backend from :setting:`STORAGES` after
- each run and passes a list of paths that have been found by the management
- command. It also receives all command line options of :djadmin:`collectstatic`.
- This is used by the
- :class:`~django.contrib.staticfiles.storage.ManifestStaticFilesStorage` by
- default.
- By default, collected files receive permissions from
- :setting:`FILE_UPLOAD_PERMISSIONS` and collected directories receive permissions
- from :setting:`FILE_UPLOAD_DIRECTORY_PERMISSIONS`. If you would like different
- permissions for these files and/or directories, you can subclass either of the
- :ref:`static files storage classes <staticfiles-storages>` and specify the
- ``file_permissions_mode`` and/or ``directory_permissions_mode`` parameters,
- respectively. For example::
- from django.contrib.staticfiles import storage
- class MyStaticFilesStorage(storage.StaticFilesStorage):
- def __init__(self, *args, **kwargs):
- kwargs["file_permissions_mode"] = 0o640
- kwargs["directory_permissions_mode"] = 0o760
- super().__init__(*args, **kwargs)
- Then set the ``staticfiles`` storage backend in :setting:`STORAGES` setting to
- ``'path.to.MyStaticFilesStorage'``.
- Some commonly used options are:
- .. django-admin-option:: --noinput, --no-input
- Do NOT prompt the user for input of any kind.
- .. django-admin-option:: --ignore PATTERN, -i PATTERN
- Ignore files, directories, or paths matching this glob-style pattern. Use
- multiple times to ignore more. When specifying a path, always use forward
- slashes, even on Windows.
- .. django-admin-option:: --dry-run, -n
- Do everything except modify the filesystem.
- .. django-admin-option:: --clear, -c
- Clear the existing files before trying to copy or link the original file.
- .. django-admin-option:: --link, -l
- Create a symbolic link to each file instead of copying.
- .. django-admin-option:: --no-post-process
- Don't call the
- :meth:`~django.contrib.staticfiles.storage.StaticFilesStorage.post_process`
- method of the configured ``staticfiles`` storage backend from
- :setting:`STORAGES`.
- .. django-admin-option:: --no-default-ignore
- Don't ignore the common private glob-style patterns ``'CVS'``, ``'.*'``
- and ``'*~'``.
- For a full list of options, refer to the commands own help by running:
- .. console::
- $ python manage.py collectstatic --help
- .. _customize-staticfiles-ignore-patterns:
- Customizing the ignored pattern list
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- The default ignored pattern list, ``['CVS', '.*', '*~']``, can be customized in
- a more persistent way than providing the ``--ignore`` command option at each
- ``collectstatic`` invocation. Provide a custom :class:`~django.apps.AppConfig`
- class, override the ``ignore_patterns`` attribute of this class and replace
- ``'django.contrib.staticfiles'`` with that class path in your
- :setting:`INSTALLED_APPS` setting::
- from django.contrib.staticfiles.apps import StaticFilesConfig
- class MyStaticFilesConfig(StaticFilesConfig):
- ignore_patterns = [...] # your custom ignore list
- ``findstatic``
- --------------
- .. django-admin:: findstatic staticfile [staticfile ...]
- Searches for one or more relative paths with the enabled finders.
- For example:
- .. console::
- $ python manage.py findstatic css/base.css admin/js/core.js
- Found 'css/base.css' here:
- /home/special.polls.com/core/static/css/base.css
- /home/polls.com/core/static/css/base.css
- Found 'admin/js/core.js' here:
- /home/polls.com/src/django/contrib/admin/media/js/core.js
- .. django-admin-option:: findstatic --first
- By default, all matching locations are found. To only return the first match
- for each relative path, use the ``--first`` option:
- .. console::
- $ python manage.py findstatic css/base.css --first
- Found 'css/base.css' here:
- /home/special.polls.com/core/static/css/base.css
- This is a debugging aid; it'll show you exactly which static file will be
- collected for a given path.
- By setting the ``--verbosity`` flag to 0, you can suppress the extra output and
- just get the path names:
- .. console::
- $ python manage.py findstatic css/base.css --verbosity 0
- /home/special.polls.com/core/static/css/base.css
- /home/polls.com/core/static/css/base.css
- On the other hand, by setting the ``--verbosity`` flag to 2, you can get all
- the directories which were searched:
- .. console::
- $ python manage.py findstatic css/base.css --verbosity 2
- Found 'css/base.css' here:
- /home/special.polls.com/core/static/css/base.css
- /home/polls.com/core/static/css/base.css
- Looking in the following locations:
- /home/special.polls.com/core/static
- /home/polls.com/core/static
- /some/other/path/static
- .. _staticfiles-runserver:
- ``runserver``
- -------------
- .. django-admin:: runserver [addrport]
- :noindex:
- Overrides the core :djadmin:`runserver` command if the ``staticfiles`` app
- is :setting:`installed<INSTALLED_APPS>` and adds automatic serving of static
- files. File serving doesn't run through :setting:`MIDDLEWARE`.
- The command adds these options:
- .. django-admin-option:: --nostatic
- Use the ``--nostatic`` option to disable serving of static files with the
- :doc:`staticfiles </ref/contrib/staticfiles>` app entirely. This option is
- only available if the :doc:`staticfiles </ref/contrib/staticfiles>` app is
- in your project's :setting:`INSTALLED_APPS` setting.
- Example usage:
- .. console::
- $ django-admin runserver --nostatic
- .. django-admin-option:: --insecure
- Use the ``--insecure`` option to force serving of static files with the
- :doc:`staticfiles </ref/contrib/staticfiles>` app even if the :setting:`DEBUG`
- setting is ``False``. By using this you acknowledge the fact that it's
- **grossly inefficient** and probably **insecure**. This is only intended for
- local development, should **never be used in production** and is only
- available if the :doc:`staticfiles </ref/contrib/staticfiles>` app is
- in your project's :setting:`INSTALLED_APPS` setting.
- ``--insecure`` doesn't work with :class:`~.storage.ManifestStaticFilesStorage`.
- Example usage:
- .. console::
- $ django-admin runserver --insecure
- .. _staticfiles-storages:
- Storages
- ========
- ``StaticFilesStorage``
- ----------------------
- .. class:: storage.StaticFilesStorage
- A subclass of the :class:`~django.core.files.storage.FileSystemStorage`
- storage backend that uses the :setting:`STATIC_ROOT` setting as the base
- file system location and the :setting:`STATIC_URL` setting respectively
- as the base URL.
- .. method:: storage.StaticFilesStorage.post_process(paths, **options)
- If this method is defined on a storage, it's called by the
- :djadmin:`collectstatic` management command after each run and gets passed the
- local storages and paths of found files as a dictionary, as well as the command
- line options. It yields tuples of three values:
- ``original_path, processed_path, processed``. The path values are strings and
- ``processed`` is a boolean indicating whether or not the value was
- post-processed, or an exception if post-processing failed.
- The :class:`~django.contrib.staticfiles.storage.ManifestStaticFilesStorage`
- uses this behind the scenes to replace the paths with their hashed
- counterparts and update the cache appropriately.
- ``ManifestStaticFilesStorage``
- ------------------------------
- .. class:: storage.ManifestStaticFilesStorage
- A subclass of the :class:`~django.contrib.staticfiles.storage.StaticFilesStorage`
- storage backend which stores the file names it handles by appending the MD5
- hash of the file's content to the filename. For example, the file
- ``css/styles.css`` would also be saved as ``css/styles.55e7cbb9ba48.css``.
- The purpose of this storage is to keep serving the old files in case some
- pages still refer to those files, e.g. because they are cached by you or
- a 3rd party proxy server. Additionally, it's very helpful if you want to
- apply `far future Expires headers`_ to the deployed files to speed up the
- load time for subsequent page visits.
- The storage backend automatically replaces the paths found in the saved
- files matching other saved files with the path of the cached copy (using
- the :meth:`~django.contrib.staticfiles.storage.StaticFilesStorage.post_process`
- method). The regular expressions used to find those paths
- (``django.contrib.staticfiles.storage.HashedFilesMixin.patterns``) cover:
- * The `@import`_ rule and `url()`_ statement of `Cascading Style Sheets`_.
- * `Source map`_ comments in CSS and JavaScript files.
- Subclass ``ManifestStaticFilesStorage`` and set the
- ``support_js_module_import_aggregation`` attribute to ``True``, if you want to
- use the experimental regular expressions to cover:
- * The `modules import`_ in JavaScript.
- * The `modules aggregation`_ in JavaScript.
- For example, the ``'css/styles.css'`` file with this content:
- .. code-block:: css
- @import url("../admin/css/base.css");
- ...would be replaced by calling the
- :meth:`~django.core.files.storage.Storage.url` method of the
- ``ManifestStaticFilesStorage`` storage backend, ultimately saving a
- ``'css/styles.55e7cbb9ba48.css'`` file with the following content:
- .. code-block:: css
- @import url("../admin/css/base.27e20196a850.css");
- .. admonition:: Usage of the ``integrity`` HTML attribute with local files
- When using the optional ``integrity`` attribute within tags like
- ``<script>`` or ``<link>``, its value should be calculated based on the
- files as they are served, not as stored in the filesystem. This is
- particularly important because depending on how static files are collected,
- their checksum may have changed (for example when using
- :djadmin:`collectstatic`). At the moment, there is no out-of-the-box
- tooling available for this.
- You can change the location of the manifest file by using a custom
- ``ManifestStaticFilesStorage`` subclass that sets the ``manifest_storage``
- argument. For example::
- from django.conf import settings
- from django.contrib.staticfiles.storage import (
- ManifestStaticFilesStorage,
- StaticFilesStorage,
- )
- class MyManifestStaticFilesStorage(ManifestStaticFilesStorage):
- def __init__(self, *args, **kwargs):
- manifest_storage = StaticFilesStorage(location=settings.BASE_DIR)
- super().__init__(*args, manifest_storage=manifest_storage, **kwargs)
- .. admonition:: References in comments
- ``ManifestStaticFilesStorage`` doesn't ignore paths in statements that are
- commented out. This :ticket:`may crash on the nonexistent paths <21080>`.
- You should check and eventually strip comments.
- .. attribute:: storage.ManifestStaticFilesStorage.manifest_hash
- This attribute provides a single hash that changes whenever a file in the
- manifest changes. This can be useful to communicate to SPAs that the assets on
- the server have changed (due to a new deployment).
- .. attribute:: storage.ManifestStaticFilesStorage.max_post_process_passes
- Since static files might reference other static files that need to have their
- paths replaced, multiple passes of replacing paths may be needed until the file
- hashes converge. To prevent an infinite loop due to hashes not converging (for
- example, if ``'foo.css'`` references ``'bar.css'`` which references
- ``'foo.css'``) there is a maximum number of passes before post-processing is
- abandoned. In cases with a large number of references, a higher number of
- passes might be needed. Increase the maximum number of passes by subclassing
- ``ManifestStaticFilesStorage`` and setting the ``max_post_process_passes``
- attribute. It defaults to 5.
- To enable the ``ManifestStaticFilesStorage`` you have to make sure the
- following requirements are met:
- * the ``staticfiles`` storage backend in :setting:`STORAGES` setting is set to
- ``'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'``
- * the :setting:`DEBUG` setting is set to ``False``
- * you've collected all your static files by using the
- :djadmin:`collectstatic` management command
- Since creating the MD5 hash can be a performance burden to your website
- during runtime, ``staticfiles`` will automatically store the mapping with
- hashed names for all processed files in a file called ``staticfiles.json``.
- This happens once when you run the :djadmin:`collectstatic` management
- command.
- .. attribute:: storage.ManifestStaticFilesStorage.manifest_strict
- If a file isn't found in the ``staticfiles.json`` manifest at runtime, a
- ``ValueError`` is raised. This behavior can be disabled by subclassing
- ``ManifestStaticFilesStorage`` and setting the ``manifest_strict`` attribute to
- ``False`` -- nonexistent paths will remain unchanged.
- Due to the requirement of running :djadmin:`collectstatic`, this storage
- typically shouldn't be used when running tests as ``collectstatic`` isn't run
- as part of the normal test setup. During testing, ensure that ``staticfiles``
- storage backend in the :setting:`STORAGES` setting is set to something else
- like ``'django.contrib.staticfiles.storage.StaticFilesStorage'`` (the default).
- .. method:: storage.ManifestStaticFilesStorage.file_hash(name, content=None)
- The method that is used when creating the hashed name of a file.
- Needs to return a hash for the given file name and content.
- By default it calculates a MD5 hash from the content's chunks as
- mentioned above. Feel free to override this method to use your own
- hashing algorithm.
- .. _`far future Expires headers`: https://developer.yahoo.com/performance/rules.html#expires
- .. _`@import`: https://www.w3.org/TR/CSS2/cascade.html#at-import
- .. _`url()`: https://www.w3.org/TR/CSS2/syndata.html#uri
- .. _`Cascading Style Sheets`: https://www.w3.org/Style/CSS/
- .. _`source map`: https://firefox-source-docs.mozilla.org/devtools-user/debugger/how_to/use_a_source_map/
- .. _`modules import`: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules#importing_features_into_your_script
- .. _`modules aggregation`: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules#aggregating_modules
- ``ManifestFilesMixin``
- ----------------------
- .. class:: storage.ManifestFilesMixin
- Use this mixin with a custom storage to append the MD5 hash of the file's
- content to the filename as :class:`~storage.ManifestStaticFilesStorage` does.
- Finders Module
- ==============
- ``staticfiles`` finders has a ``searched_locations`` attribute which is a list
- of directory paths in which the finders searched. Example usage::
- from django.contrib.staticfiles import finders
- result = finders.find("css/base.css")
- searched_locations = finders.searched_locations
- Other Helpers
- =============
- There are a few other helpers outside of the
- :mod:`staticfiles <django.contrib.staticfiles>` app to work with static
- files:
- - The :func:`django.template.context_processors.static` context processor
- which adds :setting:`STATIC_URL` to every template context rendered
- with :class:`~django.template.RequestContext` contexts.
- - The builtin template tag :ttag:`static` which takes a path and urljoins it
- with the static prefix :setting:`STATIC_URL`. If
- ``django.contrib.staticfiles`` is installed, the tag uses the ``url()``
- method of the ``staticfiles`` storage backend from :setting:`STORAGES`
- instead.
- - The builtin template tag :ttag:`get_static_prefix` which populates a
- template variable with the static prefix :setting:`STATIC_URL` to be
- used as a variable or directly.
- - The similar template tag :ttag:`get_media_prefix` which works like
- :ttag:`get_static_prefix` but uses :setting:`MEDIA_URL`.
- - The ``staticfiles`` key in :data:`django.core.files.storage.storages`
- contains a ready-to-use instance of the staticfiles storage backend.
- .. _staticfiles-development-view:
- Static file development view
- ----------------------------
- .. currentmodule:: django.contrib.staticfiles
- The static files tools are mostly designed to help with getting static files
- successfully deployed into production. This usually means a separate,
- dedicated static file server, which is a lot of overhead to mess with when
- developing locally. Thus, the ``staticfiles`` app ships with a
- **quick and dirty helper view** that you can use to serve files locally in
- development.
- .. function:: views.serve(request, path)
- This view function serves static files in development.
- .. warning::
- This view will only work if :setting:`DEBUG` is ``True``.
- That's because this view is **grossly inefficient** and probably
- **insecure**. This is only intended for local development, and should
- **never be used in production**.
- .. note::
- To guess the served files' content types, this view relies on the
- :py:mod:`mimetypes` module from the Python standard library, which itself
- relies on the underlying platform's map files. If you find that this view
- doesn't return proper content types for certain files, it is most likely
- that the platform's map files are incorrect or need to be updated. This can
- be achieved, for example, by installing or updating the ``mailcap`` package
- on a Red Hat distribution, ``mime-support`` on a Debian distribution, or by
- editing the keys under ``HKEY_CLASSES_ROOT`` in the Windows registry.
- This view is automatically enabled by :djadmin:`runserver` (with a
- :setting:`DEBUG` setting set to ``True``). To use the view with a different
- local development server, add the following snippet to the end of your
- primary URL configuration::
- from django.conf import settings
- from django.contrib.staticfiles import views
- from django.urls import re_path
- if settings.DEBUG:
- urlpatterns += [
- re_path(r"^static/(?P<path>.*)$", views.serve),
- ]
- Note, the beginning of the pattern (``r'^static/'``) should be your
- :setting:`STATIC_URL` setting.
- Since this is a bit finicky, there's also a helper function that'll do this for
- you:
- .. function:: urls.staticfiles_urlpatterns()
- This will return the proper URL pattern for serving static files to your
- already defined pattern list. Use it like this::
- from django.contrib.staticfiles.urls import staticfiles_urlpatterns
- # ... the rest of your URLconf here ...
- urlpatterns += staticfiles_urlpatterns()
- This will inspect your :setting:`STATIC_URL` setting and wire up the view
- to serve static files accordingly. Don't forget to set the
- :setting:`STATICFILES_DIRS` setting appropriately to let
- ``django.contrib.staticfiles`` know where to look for files in addition to
- files in app directories.
- .. warning::
- This helper function will only work if :setting:`DEBUG` is ``True``
- and your :setting:`STATIC_URL` setting is neither empty nor a full
- URL such as ``http://static.example.com/``.
- That's because this view is **grossly inefficient** and probably
- **insecure**. This is only intended for local development, and should
- **never be used in production**.
- Specialized test case to support 'live testing'
- -----------------------------------------------
- .. class:: testing.StaticLiveServerTestCase
- This unittest TestCase subclass extends :class:`django.test.LiveServerTestCase`.
- Just like its parent, you can use it to write tests that involve running the
- code under test and consuming it with testing tools through HTTP (e.g. Selenium,
- PhantomJS, etc.), because of which it's needed that the static assets are also
- published.
- But given the fact that it makes use of the
- :func:`django.contrib.staticfiles.views.serve` view described above, it can
- transparently overlay at test execution-time the assets provided by the
- ``staticfiles`` finders. This means you don't need to run
- :djadmin:`collectstatic` before or as a part of your tests setup.
|