diff --git a/django/contrib/admin/helpers.py b/django/contrib/admin/helpers.py index 775fb1b5d3..1217bd78df 100644 --- a/django/contrib/admin/helpers.py +++ b/django/contrib/admin/helpers.py @@ -5,7 +5,6 @@ import warnings from django import forms from django.conf import settings -from django.contrib.admin.templatetags.admin_static import static from django.contrib.admin.utils import ( display_for_field, flatten_fieldsets, help_text_for_field, label_for_field, lookup_field, @@ -77,7 +76,7 @@ class Fieldset(object): js = ['vendor/jquery/jquery%s.js' % extra, 'jquery.init.js', 'collapse%s.js' % extra] - return forms.Media(js=[static('admin/js/%s' % url) for url in js]) + return forms.Media(js=['admin/js/%s' % url for url in js]) return forms.Media() media = property(_media) diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index 24d698f540..4fb5f3ddc8 100644 --- a/django/contrib/admin/options.py +++ b/django/contrib/admin/options.py @@ -14,7 +14,6 @@ from django.contrib.admin.checks import ( BaseModelAdminChecks, InlineModelAdminChecks, ModelAdminChecks, ) from django.contrib.admin.exceptions import DisallowedModelAdminToField -from django.contrib.admin.templatetags.admin_static import static from django.contrib.admin.templatetags.admin_urls import add_preserved_filters from django.contrib.admin.utils import ( NestedObjects, flatten_fieldsets, get_deleted_objects, @@ -577,7 +576,7 @@ class ModelAdmin(BaseModelAdmin): 'prepopulate%s.js' % extra, 'vendor/xregexp/xregexp.min.js', ] - return forms.Media(js=[static('admin/js/%s' % url) for url in js]) + return forms.Media(js=['admin/js/%s' % url for url in js]) def get_model_perms(self, request): """ @@ -1820,7 +1819,7 @@ class InlineModelAdmin(BaseModelAdmin): 'inlines%s.js' % extra] if self.filter_vertical or self.filter_horizontal: js.extend(['SelectBox.js', 'SelectFilter2.js']) - return forms.Media(js=[static('admin/js/%s' % url) for url in js]) + return forms.Media(js=['admin/js/%s' % url for url in js]) def get_extra(self, request, obj=None, **kwargs): """Hook for customizing the number of extra inline forms.""" diff --git a/django/contrib/admin/templates/admin/auth/user/change_password.html b/django/contrib/admin/templates/admin/auth/user/change_password.html index 124f9279cf..3f13be2b5c 100644 --- a/django/contrib/admin/templates/admin/auth/user/change_password.html +++ b/django/contrib/admin/templates/admin/auth/user/change_password.html @@ -1,5 +1,5 @@ {% extends "admin/base_site.html" %} -{% load i18n admin_static %} +{% load i18n static %} {% load admin_urls %} {% block extrahead %}{{ block.super }} diff --git a/django/contrib/admin/templates/admin/base.html b/django/contrib/admin/templates/admin/base.html index ad8663f00d..70e137cfe2 100644 --- a/django/contrib/admin/templates/admin/base.html +++ b/django/contrib/admin/templates/admin/base.html @@ -1,4 +1,4 @@ -{% load i18n admin_static %}<!DOCTYPE html> +{% load i18n static %}<!DOCTYPE html> {% get_current_language as LANGUAGE_CODE %}{% get_current_language_bidi as LANGUAGE_BIDI %} <html lang="{{ LANGUAGE_CODE|default:"en-us" }}" {% if LANGUAGE_BIDI %}dir="rtl"{% endif %}> <head> diff --git a/django/contrib/admin/templates/admin/change_form.html b/django/contrib/admin/templates/admin/change_form.html index 60c68f1d03..82b495c0b6 100644 --- a/django/contrib/admin/templates/admin/change_form.html +++ b/django/contrib/admin/templates/admin/change_form.html @@ -1,5 +1,5 @@ {% extends "admin/base_site.html" %} -{% load i18n admin_urls admin_static admin_modify %} +{% load i18n admin_urls static admin_modify %} {% block extrahead %}{{ block.super }} <script type="text/javascript" src="{% url 'admin:jsi18n' %}"></script> diff --git a/django/contrib/admin/templates/admin/change_list.html b/django/contrib/admin/templates/admin/change_list.html index 5d73d74808..1ea38d8117 100644 --- a/django/contrib/admin/templates/admin/change_list.html +++ b/django/contrib/admin/templates/admin/change_list.html @@ -1,5 +1,5 @@ {% extends "admin/base_site.html" %} -{% load i18n admin_urls admin_static admin_list %} +{% load i18n admin_urls static admin_list %} {% block extrastyle %} {{ block.super }} diff --git a/django/contrib/admin/templates/admin/change_list_results.html b/django/contrib/admin/templates/admin/change_list_results.html index e3d4b2549a..b3d7dd01d3 100644 --- a/django/contrib/admin/templates/admin/change_list_results.html +++ b/django/contrib/admin/templates/admin/change_list_results.html @@ -1,4 +1,4 @@ -{% load i18n admin_static %} +{% load i18n static %} {% if result_hidden_fields %} <div class="hiddenfields">{# DIV for HTML validation #} {% for item in result_hidden_fields %}{{ item }}{% endfor %} diff --git a/django/contrib/admin/templates/admin/delete_confirmation.html b/django/contrib/admin/templates/admin/delete_confirmation.html index baaf75b2a0..414b2a0bb5 100644 --- a/django/contrib/admin/templates/admin/delete_confirmation.html +++ b/django/contrib/admin/templates/admin/delete_confirmation.html @@ -1,5 +1,5 @@ {% extends "admin/base_site.html" %} -{% load i18n admin_urls admin_static %} +{% load i18n admin_urls static %} {% block extrahead %} {{ media }} diff --git a/django/contrib/admin/templates/admin/delete_selected_confirmation.html b/django/contrib/admin/templates/admin/delete_selected_confirmation.html index 27a888f154..00ee2e79e3 100644 --- a/django/contrib/admin/templates/admin/delete_selected_confirmation.html +++ b/django/contrib/admin/templates/admin/delete_selected_confirmation.html @@ -1,5 +1,5 @@ {% extends "admin/base_site.html" %} -{% load i18n l10n admin_urls admin_static %} +{% load i18n l10n admin_urls static %} {% block extrahead %} {{ media }} diff --git a/django/contrib/admin/templates/admin/edit_inline/stacked.html b/django/contrib/admin/templates/admin/edit_inline/stacked.html index 799ea3b4de..9025a17afb 100644 --- a/django/contrib/admin/templates/admin/edit_inline/stacked.html +++ b/django/contrib/admin/templates/admin/edit_inline/stacked.html @@ -1,4 +1,4 @@ -{% load i18n admin_urls admin_static %} +{% load i18n admin_urls static %} <div class="js-inline-admin-formset inline-group" id="{{ inline_admin_formset.formset.prefix }}-group" data-inline-type="stacked" diff --git a/django/contrib/admin/templates/admin/edit_inline/tabular.html b/django/contrib/admin/templates/admin/edit_inline/tabular.html index 8bb3f60c73..bcf3e6bd1c 100644 --- a/django/contrib/admin/templates/admin/edit_inline/tabular.html +++ b/django/contrib/admin/templates/admin/edit_inline/tabular.html @@ -1,4 +1,4 @@ -{% load i18n admin_urls admin_static admin_modify %} +{% load i18n admin_urls static admin_modify %} <div class="js-inline-admin-formset inline-group" id="{{ inline_admin_formset.formset.prefix }}-group" data-inline-type="tabular" data-inline-formset="{{ inline_admin_formset.inline_formset_data }}"> diff --git a/django/contrib/admin/templates/admin/index.html b/django/contrib/admin/templates/admin/index.html index fba67d78a4..919ea46cfc 100644 --- a/django/contrib/admin/templates/admin/index.html +++ b/django/contrib/admin/templates/admin/index.html @@ -1,5 +1,5 @@ {% extends "admin/base_site.html" %} -{% load i18n admin_static %} +{% load i18n static %} {% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% static "admin/css/dashboard.css" %}" />{% endblock %} diff --git a/django/contrib/admin/templates/admin/login.html b/django/contrib/admin/templates/admin/login.html index f8653e556e..a955c871f7 100644 --- a/django/contrib/admin/templates/admin/login.html +++ b/django/contrib/admin/templates/admin/login.html @@ -1,5 +1,5 @@ {% extends "admin/base_site.html" %} -{% load i18n admin_static %} +{% load i18n static %} {% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% static "admin/css/login.css" %}" /> {{ form.media }} diff --git a/django/contrib/admin/templates/admin/popup_response.html b/django/contrib/admin/templates/admin/popup_response.html index 6be1159cd4..6e4fac8e8d 100644 --- a/django/contrib/admin/templates/admin/popup_response.html +++ b/django/contrib/admin/templates/admin/popup_response.html @@ -1,4 +1,4 @@ -{% load i18n admin_static %}<!DOCTYPE html> +{% load i18n static %}<!DOCTYPE html> <html> <head><title>{% trans 'Popup closing...' %}</title></head> <body> diff --git a/django/contrib/admin/templates/admin/prepopulated_fields_js.html b/django/contrib/admin/templates/admin/prepopulated_fields_js.html index 508066a9da..157233993f 100644 --- a/django/contrib/admin/templates/admin/prepopulated_fields_js.html +++ b/django/contrib/admin/templates/admin/prepopulated_fields_js.html @@ -1,4 +1,4 @@ -{% load l10n admin_static %} +{% load l10n static %} <script type="text/javascript" id="django-admin-prepopulated-fields-constants" src="{% static "admin/js/prepopulate_init.js" %}" diff --git a/django/contrib/admin/templates/admin/related_widget_wrapper.html b/django/contrib/admin/templates/admin/related_widget_wrapper.html index 502bede036..f690d7c2b7 100644 --- a/django/contrib/admin/templates/admin/related_widget_wrapper.html +++ b/django/contrib/admin/templates/admin/related_widget_wrapper.html @@ -1,4 +1,4 @@ -{% load i18n admin_static %} +{% load i18n static %} <div class="related-widget-wrapper"> {{ widget }} {% block links %} diff --git a/django/contrib/admin/templates/admin/search_form.html b/django/contrib/admin/templates/admin/search_form.html index be192919a9..1417c1f599 100644 --- a/django/contrib/admin/templates/admin/search_form.html +++ b/django/contrib/admin/templates/admin/search_form.html @@ -1,4 +1,4 @@ -{% load i18n admin_static %} +{% load i18n static %} {% if cl.search_fields %} <div id="toolbar"><form id="changelist-search" method="get"> <div><!-- DIV needed for valid HTML --> diff --git a/django/contrib/admin/templates/registration/password_change_form.html b/django/contrib/admin/templates/registration/password_change_form.html index f005f71233..cbbf67fbf2 100644 --- a/django/contrib/admin/templates/registration/password_change_form.html +++ b/django/contrib/admin/templates/registration/password_change_form.html @@ -1,5 +1,5 @@ {% extends "admin/base_site.html" %} -{% load i18n admin_static %} +{% load i18n static %} {% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% static "admin/css/forms.css" %}" />{% endblock %} {% block userlinks %}{% url 'django-admindocs-docroot' as docsroot %}{% if docsroot %}<a href="{{ docsroot }}">{% trans 'Documentation' %}</a> / {% endif %} {% trans 'Change password' %} / <a href="{% url 'admin:logout' %}">{% trans 'Log out' %}</a>{% endblock %} {% block breadcrumbs %} diff --git a/django/contrib/admin/templatetags/admin_list.py b/django/contrib/admin/templatetags/admin_list.py index d3fcafc3af..9cf279fa40 100644 --- a/django/contrib/admin/templatetags/admin_list.py +++ b/django/contrib/admin/templatetags/admin_list.py @@ -3,7 +3,6 @@ from __future__ import unicode_literals import datetime import warnings -from django.contrib.admin.templatetags.admin_static import static from django.contrib.admin.templatetags.admin_urls import add_preserved_filters from django.contrib.admin.utils import ( display_for_field, display_for_value, label_for_field, lookup_field, @@ -16,6 +15,7 @@ from django.core.urlresolvers import NoReverseMatch from django.db import models from django.template import Library from django.template.loader import get_template +from django.templatetags.static import static from django.utils import formats from django.utils.deprecation import RemovedInDjango20Warning from django.utils.encoding import force_text diff --git a/django/contrib/admin/templatetags/admin_static.py b/django/contrib/admin/templatetags/admin_static.py index b767dc7459..cfd55c737b 100644 --- a/django/contrib/admin/templatetags/admin_static.py +++ b/django/contrib/admin/templatetags/admin_static.py @@ -1,17 +1,11 @@ -from django.apps import apps from django.template import Library +from django.templatetags.static import static as _static register = Library() -_static = None - @register.simple_tag def static(path): - global _static - if _static is None: - if apps.is_installed('django.contrib.staticfiles'): - from django.contrib.staticfiles.templatetags.staticfiles import static as _static - else: - from django.templatetags.static import static as _static + # Backwards compatibility alias for django.templatetags.static.static(). + # Deprecation should start in Django 2.0. return _static(path) diff --git a/django/contrib/admin/widgets.py b/django/contrib/admin/widgets.py index e6c13a53f1..3397e08a4b 100644 --- a/django/contrib/admin/widgets.py +++ b/django/contrib/admin/widgets.py @@ -6,7 +6,6 @@ from __future__ import unicode_literals import copy from django import forms -from django.contrib.admin.templatetags.admin_static import static from django.core.urlresolvers import reverse from django.db.models.deletion import CASCADE from django.forms.utils import flatatt @@ -32,7 +31,7 @@ class FilteredSelectMultiple(forms.SelectMultiple): @property def media(self): js = ["core.js", "SelectBox.js", "SelectFilter2.js"] - return forms.Media(js=[static("admin/js/%s" % path) for path in js]) + return forms.Media(js=["admin/js/%s" % path for path in js]) def __init__(self, verbose_name, is_stacked, attrs=None, choices=()): self.verbose_name = verbose_name @@ -56,7 +55,7 @@ class AdminDateWidget(forms.DateInput): @property def media(self): js = ["calendar.js", "admin/DateTimeShortcuts.js"] - return forms.Media(js=[static("admin/js/%s" % path) for path in js]) + return forms.Media(js=["admin/js/%s" % path for path in js]) def __init__(self, attrs=None, format=None): final_attrs = {'class': 'vDateField', 'size': '10'} @@ -69,7 +68,7 @@ class AdminTimeWidget(forms.TimeInput): @property def media(self): js = ["calendar.js", "admin/DateTimeShortcuts.js"] - return forms.Media(js=[static("admin/js/%s" % path) for path in js]) + return forms.Media(js=["admin/js/%s" % path for path in js]) def __init__(self, attrs=None, format=None): final_attrs = {'class': 'vTimeField', 'size': '8'} diff --git a/django/contrib/staticfiles/templatetags/staticfiles.py b/django/contrib/staticfiles/templatetags/staticfiles.py index e3bea9328f..eeb7452dbf 100644 --- a/django/contrib/staticfiles/templatetags/staticfiles.py +++ b/django/contrib/staticfiles/templatetags/staticfiles.py @@ -1,36 +1,19 @@ from django import template -from django.contrib.staticfiles.storage import staticfiles_storage -from django.templatetags.static import StaticNode +from django.templatetags.static import ( + do_static as _do_static, static as _static, +) register = template.Library() def static(path): - return staticfiles_storage.url(path) - - -class StaticFilesNode(StaticNode): - - def url(self, context): - path = self.path.resolve(context) - return static(path) + # Backwards compatibility alias for django.templatetags.static.static(). + # Deprecation should start in Django 2.0. + return _static(path) @register.tag('static') def do_static(parser, token): - """ - A template tag that returns the URL to a file - using staticfiles' storage backend - - Usage:: - - {% static path [as varname] %} - - Examples:: - - {% static "myapp/css/base.css" %} - {% static variable_with_path %} - {% static "myapp/css/base.css" as admin_base_css %} - {% static variable_with_path as varname %} - """ - return StaticFilesNode.handle_token(parser, token) + # Backwards compatibility alias for django.templatetags.static.do_static(). + # Deprecation should start in Django 2.0. + return _do_static(parser, token) diff --git a/django/forms/widgets.py b/django/forms/widgets.py index 3e6de0455c..f52ced26c1 100644 --- a/django/forms/widgets.py +++ b/django/forms/widgets.py @@ -11,6 +11,7 @@ from itertools import chain from django.conf import settings from django.forms.utils import flatatt, to_current_timezone +from django.templatetags.static import static from django.utils import datetime_safe, formats, six from django.utils.datastructures import MultiValueDict from django.utils.dates import MONTHS @@ -21,7 +22,6 @@ from django.utils.formats import get_format from django.utils.html import conditional_escape, format_html, html_safe from django.utils.safestring import mark_safe from django.utils.six.moves import range -from django.utils.six.moves.urllib.parse import urljoin from django.utils.translation import ugettext_lazy __all__ = ( @@ -77,12 +77,15 @@ class Media(object): ) for path in self._css[medium] ] for medium in media]) - def absolute_path(self, path, prefix=None): + def absolute_path(self, path): + """ + Given a relative or absolute path to a static asset, return an absolute + path. An absolute path will be returned unchanged while a relative path + will be passed to django.templatetags.static.static(). + """ if path.startswith(('http://', 'https://', '/')): return path - if prefix is None: - prefix = settings.STATIC_URL - return urljoin(prefix, path) + return static(path) def __getitem__(self, name): "Returns a Media object that only contains media of the given type" diff --git a/django/templatetags/static.py b/django/templatetags/static.py index 7541adb35e..1e57e5a8d7 100644 --- a/django/templatetags/static.py +++ b/django/templatetags/static.py @@ -1,4 +1,5 @@ from django import template +from django.apps import apps from django.utils.encoding import iri_to_uri from django.utils.six.moves.urllib.parse import urljoin @@ -108,7 +109,11 @@ class StaticNode(template.Node): @classmethod def handle_simple(cls, path): - return urljoin(PrefixNode.handle_simple("STATIC_URL"), path) + if apps.is_installed('django.contrib.staticfiles'): + from django.contrib.staticfiles.storage import staticfiles_storage + return staticfiles_storage.url(path) + else: + return urljoin(PrefixNode.handle_simple("STATIC_URL"), path) @classmethod def handle_token(cls, parser, token): @@ -151,4 +156,8 @@ def do_static(parser, token): def static(path): + """ + Given a relative path to a static asset, return the absolute path to the + asset. + """ return StaticNode.handle_simple(path) diff --git a/docs/howto/static-files/index.txt b/docs/howto/static-files/index.txt index e9a7c7c0a1..4faeed4714 100644 --- a/docs/howto/static-files/index.txt +++ b/docs/howto/static-files/index.txt @@ -19,17 +19,17 @@ Configuring static files STATIC_URL = '/static/' 3. In your templates, either hardcode the url like - ``/static/my_app/myexample.jpg`` or, preferably, use the - :ttag:`static<staticfiles-static>` template tag to build the URL for the given - relative path by using the configured :setting:`STATICFILES_STORAGE` storage - (this makes it much easier when you want to switch to a content delivery - network (CDN) for serving static files). + ``/static/my_app/myexample.jpg`` or, preferably, use the :ttag:`static` + template tag to build the URL for the given relative path by using the + configured :setting:`STATICFILES_STORAGE` storage (this makes it much easier + when you want to switch to a content delivery network (CDN) for serving + static files). .. _staticfiles-in-templates: .. code-block:: html+django - {% load staticfiles %} + {% load static %} <img src="{% static "my_app/myexample.jpg" %}" alt="My image"/> 4. Store your static files in a folder called ``static`` in your app. For diff --git a/docs/intro/overview.txt b/docs/intro/overview.txt index b43bf38860..94eaec136f 100644 --- a/docs/intro/overview.txt +++ b/docs/intro/overview.txt @@ -304,7 +304,7 @@ Here's what the "base.html" template, including the use of :doc:`static files .. snippet:: html+django :filename: mysite/templates/base.html - {% load staticfiles %} + {% load static %} <html> <head> <title>{% block title %}{% endblock %}</title> diff --git a/docs/intro/tutorial06.txt b/docs/intro/tutorial06.txt index de5daae467..0d3dd23315 100644 --- a/docs/intro/tutorial06.txt +++ b/docs/intro/tutorial06.txt @@ -68,13 +68,11 @@ Next, add the following at the top of ``polls/templates/polls/index.html``: .. snippet:: html+django :filename: polls/templates/polls/index.html - {% load staticfiles %} + {% load static %} <link rel="stylesheet" type="text/css" href="{% static 'polls/style.css' %}" /> -``{% load staticfiles %}`` loads the :ttag:`{% static %} <staticfiles-static>` -template tag from the ``staticfiles`` template library. The ``{% static %}`` -template tag generates the absolute URL of the static file. +The ``{% static %}`` template tag generates the absolute URL of static files. That's all you need to do for development. Reload ``http://localhost:8000/polls/`` and you should see that the question links are diff --git a/docs/ref/contrib/admin/javascript.txt b/docs/ref/contrib/admin/javascript.txt index b517aa18cc..8b14b781c9 100644 --- a/docs/ref/contrib/admin/javascript.txt +++ b/docs/ref/contrib/admin/javascript.txt @@ -26,7 +26,7 @@ In your custom ``change_form.html`` template, extend the .. code-block:: html+django {% extends 'admin/change_form.html' %} - {% load admin_static %} + {% load static %} {% block admin_change_form_document_ready %} {{ block.super }} @@ -65,7 +65,7 @@ namespace, just listen to the event triggered from there. For example: .. code-block:: html+django {% extends 'admin/change_form.html' %} - {% load admin_static %} + {% load static %} {% block admin_change_form_document_ready %} {{ block.super }} diff --git a/docs/ref/contrib/staticfiles.txt b/docs/ref/contrib/staticfiles.txt index 010eacccce..e6caa53e32 100644 --- a/docs/ref/contrib/staticfiles.txt +++ b/docs/ref/contrib/staticfiles.txt @@ -285,11 +285,16 @@ following requirements are met: * the :setting:`STATICFILES_STORAGE` setting is set to ``'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'`` * the :setting:`DEBUG` setting is set to ``False`` -* you use the ``staticfiles`` :ttag:`static<staticfiles-static>` template - tag to refer to your static files in your templates * you've collected all your static files by using the :djadmin:`collectstatic` management command +.. versionchanged:: 1.10 + + In older versions, you also had to use + ``{% load static from staticfiles %}`` in your template. The + :ttag:`static` template tag (``{% load static %}``) now uses + :mod:`django.contrib.staticfiles` if it's installed. + 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``. @@ -331,43 +336,6 @@ If you want to override certain options of the cache backend the storage uses, simply specify a custom entry in the :setting:`CACHES` setting named ``'staticfiles'``. It falls back to using the ``'default'`` cache backend. -.. currentmodule:: django.contrib.staticfiles.templatetags.staticfiles - -Template tags -============= - -static ------- - -.. templatetag:: staticfiles-static - -Uses the configured :setting:`STATICFILES_STORAGE` storage to create the -full URL for the given relative path, e.g.: - -.. code-block:: html+django - - {% load static from staticfiles %} - <img src="{% static "images/hi.jpg" %}" alt="Hi!" /> - -The previous example is equal to calling the ``url`` method of an instance of -:setting:`STATICFILES_STORAGE` with ``"images/hi.jpg"``. This is especially -useful when using a non-local storage backend to deploy files as documented -in :ref:`staticfiles-from-cdn`. - -If you'd like to retrieve a static URL without displaying it, you can use a -slightly different call: - -.. code-block:: html+django - - {% load static from staticfiles %} - {% static "images/hi.jpg" as myphoto %} - <img src="{{ myphoto }}" alt="Hi!" /> - -.. admonition:: Using Jinja2 templates? - - See :class:`django.template.backends.jinja2.Jinja2` for information on - using the ``static`` tag with Jinja2. - Finders Module ============== @@ -390,8 +358,10 @@ files: 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`. +- 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 :setting:`STATICFILES_STORAGE` instead. - The builtin template tag :ttag:`get_static_prefix` which populates a template variable with the static prefix :setting:`STATIC_URL` to be diff --git a/docs/ref/templates/builtins.txt b/docs/ref/templates/builtins.txt index 680f9eda9b..da6df4472f 100644 --- a/docs/ref/templates/builtins.txt +++ b/docs/ref/templates/builtins.txt @@ -2399,8 +2399,9 @@ static """""" To link to static files that are saved in :setting:`STATIC_ROOT` Django ships -with a :ttag:`static` template tag. You can use this regardless if you're -using :class:`~django.template.RequestContext` or not. For example:: +with a :ttag:`static` template tag. If the :mod:`django.contrib.staticfiles` +app is installed, the tag will serve files using ``url()`` method of the +storage specified by :setting:`STATICFILES_STORAGE`. For example:: {% load static %} <img src="{% static "images/hi.jpg" %}" alt="Hi!" /> @@ -2418,18 +2419,16 @@ slightly different call:: {% static "images/hi.jpg" as myphoto %} <img src="{{ myphoto }}"></img> -.. note:: +.. admonition:: Using Jinja2 templates? - The :mod:`staticfiles<django.contrib.staticfiles>` contrib app also ships - with a :ttag:`static template tag<staticfiles-static>` which uses - ``staticfiles'`` :setting:`STATICFILES_STORAGE` to build the URL of the - given path (rather than simply using :func:`urllib.parse.urljoin` with the - :setting:`STATIC_URL` setting and the given path). Use that instead if you - have an advanced use case such as :ref:`using a cloud service to serve - static files<staticfiles-from-cdn>`:: + See :class:`~django.template.backends.jinja2.Jinja2` for information on + using the ``static`` tag with Jinja2. - {% load static from staticfiles %} - <img src="{% static "images/hi.jpg" %}" alt="Hi!" /> +.. versionchanged:: 1.10 + + In older versions, you had to use ``{% load static from staticfiles %}`` in + your template to serve files from the storage defined in + :setting:`STATICFILES_STORAGE`. This is no longer required. .. templatetag:: get_static_prefix diff --git a/docs/releases/1.10.txt b/docs/releases/1.10.txt index bee3b1d41f..e86a061f6e 100644 --- a/docs/releases/1.10.txt +++ b/docs/releases/1.10.txt @@ -127,7 +127,11 @@ Minor features :mod:`django.contrib.staticfiles` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -* ... +* The :ttag:`static` template tag now uses ``django.contrib.staticfiles`` + if it's in ``INSTALLED_APPS``. This is especially useful for third-party apps + which can now always use ``{% load static %}`` (instead of + ``{% load staticfiles %}`` or ``{% load static from staticfiles %}``) and + not worry about whether or not the ``staticfiles`` app is installed. :mod:`django.contrib.syndication` ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -169,7 +173,8 @@ File Uploads Forms ^^^^^ -* ... +* Form and widget ``Media`` is now served using + :mod:`django.contrib.staticfiles` if installed. Generic Views ^^^^^^^^^^^^^ diff --git a/docs/releases/1.4.txt b/docs/releases/1.4.txt index 3f0001152f..9f73a42ae6 100644 --- a/docs/releases/1.4.txt +++ b/docs/releases/1.4.txt @@ -459,10 +459,10 @@ more details. ~~~~~~~~~~~~~~~~~~~~~~~ The :mod:`staticfiles<django.contrib.staticfiles>` contrib app has a new -:ttag:`static<staticfiles-static>` template tag to refer to files saved with -the :setting:`STATICFILES_STORAGE` storage backend. It uses the storage -backend's ``url`` method and therefore supports advanced features such as -:ref:`serving files from a cloud service<staticfiles-from-cdn>`. +``static`` template tag to refer to files saved with the +:setting:`STATICFILES_STORAGE` storage backend. It uses the storage backend's +``url`` method and therefore supports advanced features such as :ref:`serving +files from a cloud service<staticfiles-from-cdn>`. ``CachedStaticFilesStorage`` storage backend ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/docs/topics/forms/media.txt b/docs/topics/forms/media.txt index a7975b4bce..180cd92995 100644 --- a/docs/topics/forms/media.txt +++ b/docs/topics/forms/media.txt @@ -203,12 +203,13 @@ Paths in asset definitions Paths used to specify assets can be either relative or absolute. If a path starts with ``/``, ``http://`` or ``https://``, it will be interpreted as an absolute path, and left as-is. All other paths will -be prepended with the value of the appropriate prefix. +be prepended with the value of the appropriate prefix. If the +:mod:`django.contrib.staticfiles` app is installed, it will be used to serve +assets. -As part of the introduction of the -:doc:`staticfiles app </ref/contrib/staticfiles>` two new settings were added -to refer to "static files" (images, CSS, JavaScript, etc.) that are needed -to render a complete web page: :setting:`STATIC_URL` and :setting:`STATIC_ROOT`. +Whether or not you use :mod:`django.contrib.staticfiles`, the +:setting:`STATIC_URL` and :setting:`STATIC_ROOT` settings are required to +render a complete web page. To find the appropriate prefix to use, Django will check if the :setting:`STATIC_URL` setting is not ``None`` and automatically fall back @@ -238,6 +239,18 @@ But if :setting:`STATIC_URL` is ``'http://static.example.com/'``:: <script type="text/javascript" src="http://static.example.com/animations.js"></script> <script type="text/javascript" src="http://othersite.com/actions.js"></script> +Or if :mod:`~django.contrib.staticfiles` is configured using the +`~django.contib.staticfiles.ManifestStaticFilesStorage`:: + + >>> w = CalendarWidget() + >>> print(w.media) + <link href="/css/pretty.css" type="text/css" media="all" rel="stylesheet" /> + <script type="text/javascript" src="https://static.example.com/animations.27e20196a850.js"></script> + <script type="text/javascript" src="http://othersite.com/actions.js"></script> + +.. versionchanged:: 1.10 + + Older versions didn't serve assets using :mod:`django.contrib.staticfiles`. ``Media`` objects ----------------- diff --git a/tests/staticfiles_tests/test_forms.py b/tests/staticfiles_tests/test_forms.py new file mode 100644 index 0000000000..f5bd24186b --- /dev/null +++ b/tests/staticfiles_tests/test_forms.py @@ -0,0 +1,30 @@ +from django.contrib.staticfiles import storage +from django.forms import Media +from django.test import SimpleTestCase, override_settings +from django.utils.six.moves.urllib.parse import urljoin + + +class StaticTestStorage(storage.StaticFilesStorage): + def url(self, name): + return urljoin('https://example.com/assets/', name) + + +@override_settings( + STATIC_URL='http://media.example.com/static/', + INSTALLED_APPS=('django.contrib.staticfiles', ), + STATICFILES_STORAGE='staticfiles_tests.test_forms.StaticTestStorage', +) +class StaticFilesFormsMediaTestCase(SimpleTestCase): + def test_absolute_url(self): + m = Media( + css={'all': ('path/to/css1', '/path/to/css2')}, + js=('/path/to/js1', 'http://media.other.com/path/to/js2', 'https://secure.other.com/path/to/js3'), + ) + self.assertEqual( + str(m), + """<link href="https://example.com/assets/path/to/css1" type="text/css" media="all" rel="stylesheet" /> +<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" /> +<script type="text/javascript" src="/path/to/js1"></script> +<script type="text/javascript" src="http://media.other.com/path/to/js2"></script> +<script type="text/javascript" src="https://secure.other.com/path/to/js3"></script>""" + )