mirror of https://github.com/django/django.git
Fixed #21221 -- Made form Media and static template tag use staticfiles if installed.
This commit is contained in:
parent
6be9589eb3
commit
cf546e11ac
|
@ -5,7 +5,6 @@ import warnings
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.admin.templatetags.admin_static import static
|
|
||||||
from django.contrib.admin.utils import (
|
from django.contrib.admin.utils import (
|
||||||
display_for_field, flatten_fieldsets, help_text_for_field, label_for_field,
|
display_for_field, flatten_fieldsets, help_text_for_field, label_for_field,
|
||||||
lookup_field,
|
lookup_field,
|
||||||
|
@ -77,7 +76,7 @@ class Fieldset(object):
|
||||||
js = ['vendor/jquery/jquery%s.js' % extra,
|
js = ['vendor/jquery/jquery%s.js' % extra,
|
||||||
'jquery.init.js',
|
'jquery.init.js',
|
||||||
'collapse%s.js' % extra]
|
'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()
|
return forms.Media()
|
||||||
media = property(_media)
|
media = property(_media)
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,6 @@ from django.contrib.admin.checks import (
|
||||||
BaseModelAdminChecks, InlineModelAdminChecks, ModelAdminChecks,
|
BaseModelAdminChecks, InlineModelAdminChecks, ModelAdminChecks,
|
||||||
)
|
)
|
||||||
from django.contrib.admin.exceptions import DisallowedModelAdminToField
|
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.templatetags.admin_urls import add_preserved_filters
|
||||||
from django.contrib.admin.utils import (
|
from django.contrib.admin.utils import (
|
||||||
NestedObjects, flatten_fieldsets, get_deleted_objects,
|
NestedObjects, flatten_fieldsets, get_deleted_objects,
|
||||||
|
@ -577,7 +576,7 @@ class ModelAdmin(BaseModelAdmin):
|
||||||
'prepopulate%s.js' % extra,
|
'prepopulate%s.js' % extra,
|
||||||
'vendor/xregexp/xregexp.min.js',
|
'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):
|
def get_model_perms(self, request):
|
||||||
"""
|
"""
|
||||||
|
@ -1820,7 +1819,7 @@ class InlineModelAdmin(BaseModelAdmin):
|
||||||
'inlines%s.js' % extra]
|
'inlines%s.js' % extra]
|
||||||
if self.filter_vertical or self.filter_horizontal:
|
if self.filter_vertical or self.filter_horizontal:
|
||||||
js.extend(['SelectBox.js', 'SelectFilter2.js'])
|
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):
|
def get_extra(self, request, obj=None, **kwargs):
|
||||||
"""Hook for customizing the number of extra inline forms."""
|
"""Hook for customizing the number of extra inline forms."""
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{% extends "admin/base_site.html" %}
|
{% extends "admin/base_site.html" %}
|
||||||
{% load i18n admin_static %}
|
{% load i18n static %}
|
||||||
{% load admin_urls %}
|
{% load admin_urls %}
|
||||||
|
|
||||||
{% block extrahead %}{{ block.super }}
|
{% block extrahead %}{{ block.super }}
|
||||||
|
|
|
@ -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 %}
|
{% 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 %}>
|
<html lang="{{ LANGUAGE_CODE|default:"en-us" }}" {% if LANGUAGE_BIDI %}dir="rtl"{% endif %}>
|
||||||
<head>
|
<head>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{% extends "admin/base_site.html" %}
|
{% extends "admin/base_site.html" %}
|
||||||
{% load i18n admin_urls admin_static admin_modify %}
|
{% load i18n admin_urls static admin_modify %}
|
||||||
|
|
||||||
{% block extrahead %}{{ block.super }}
|
{% block extrahead %}{{ block.super }}
|
||||||
<script type="text/javascript" src="{% url 'admin:jsi18n' %}"></script>
|
<script type="text/javascript" src="{% url 'admin:jsi18n' %}"></script>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{% extends "admin/base_site.html" %}
|
{% extends "admin/base_site.html" %}
|
||||||
{% load i18n admin_urls admin_static admin_list %}
|
{% load i18n admin_urls static admin_list %}
|
||||||
|
|
||||||
{% block extrastyle %}
|
{% block extrastyle %}
|
||||||
{{ block.super }}
|
{{ block.super }}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% load i18n admin_static %}
|
{% load i18n static %}
|
||||||
{% if result_hidden_fields %}
|
{% if result_hidden_fields %}
|
||||||
<div class="hiddenfields">{# DIV for HTML validation #}
|
<div class="hiddenfields">{# DIV for HTML validation #}
|
||||||
{% for item in result_hidden_fields %}{{ item }}{% endfor %}
|
{% for item in result_hidden_fields %}{{ item }}{% endfor %}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{% extends "admin/base_site.html" %}
|
{% extends "admin/base_site.html" %}
|
||||||
{% load i18n admin_urls admin_static %}
|
{% load i18n admin_urls static %}
|
||||||
|
|
||||||
{% block extrahead %}
|
{% block extrahead %}
|
||||||
{{ media }}
|
{{ media }}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{% extends "admin/base_site.html" %}
|
{% extends "admin/base_site.html" %}
|
||||||
{% load i18n l10n admin_urls admin_static %}
|
{% load i18n l10n admin_urls static %}
|
||||||
|
|
||||||
{% block extrahead %}
|
{% block extrahead %}
|
||||||
{{ media }}
|
{{ media }}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% load i18n admin_urls admin_static %}
|
{% load i18n admin_urls static %}
|
||||||
<div class="js-inline-admin-formset inline-group"
|
<div class="js-inline-admin-formset inline-group"
|
||||||
id="{{ inline_admin_formset.formset.prefix }}-group"
|
id="{{ inline_admin_formset.formset.prefix }}-group"
|
||||||
data-inline-type="stacked"
|
data-inline-type="stacked"
|
||||||
|
|
|
@ -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"
|
<div class="js-inline-admin-formset inline-group" id="{{ inline_admin_formset.formset.prefix }}-group"
|
||||||
data-inline-type="tabular"
|
data-inline-type="tabular"
|
||||||
data-inline-formset="{{ inline_admin_formset.inline_formset_data }}">
|
data-inline-formset="{{ inline_admin_formset.inline_formset_data }}">
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{% extends "admin/base_site.html" %}
|
{% 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 %}
|
{% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% static "admin/css/dashboard.css" %}" />{% endblock %}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{% extends "admin/base_site.html" %}
|
{% 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" %}" />
|
{% block extrastyle %}{{ block.super }}<link rel="stylesheet" type="text/css" href="{% static "admin/css/login.css" %}" />
|
||||||
{{ form.media }}
|
{{ form.media }}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% load i18n admin_static %}<!DOCTYPE html>
|
{% load i18n static %}<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head><title>{% trans 'Popup closing...' %}</title></head>
|
<head><title>{% trans 'Popup closing...' %}</title></head>
|
||||||
<body>
|
<body>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% load l10n admin_static %}
|
{% load l10n static %}
|
||||||
<script type="text/javascript"
|
<script type="text/javascript"
|
||||||
id="django-admin-prepopulated-fields-constants"
|
id="django-admin-prepopulated-fields-constants"
|
||||||
src="{% static "admin/js/prepopulate_init.js" %}"
|
src="{% static "admin/js/prepopulate_init.js" %}"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% load i18n admin_static %}
|
{% load i18n static %}
|
||||||
<div class="related-widget-wrapper">
|
<div class="related-widget-wrapper">
|
||||||
{{ widget }}
|
{{ widget }}
|
||||||
{% block links %}
|
{% block links %}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{% load i18n admin_static %}
|
{% load i18n static %}
|
||||||
{% if cl.search_fields %}
|
{% if cl.search_fields %}
|
||||||
<div id="toolbar"><form id="changelist-search" method="get">
|
<div id="toolbar"><form id="changelist-search" method="get">
|
||||||
<div><!-- DIV needed for valid HTML -->
|
<div><!-- DIV needed for valid HTML -->
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{% extends "admin/base_site.html" %}
|
{% 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 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 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 %}
|
{% block breadcrumbs %}
|
||||||
|
|
|
@ -3,7 +3,6 @@ from __future__ import unicode_literals
|
||||||
import datetime
|
import datetime
|
||||||
import warnings
|
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.templatetags.admin_urls import add_preserved_filters
|
||||||
from django.contrib.admin.utils import (
|
from django.contrib.admin.utils import (
|
||||||
display_for_field, display_for_value, label_for_field, lookup_field,
|
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.db import models
|
||||||
from django.template import Library
|
from django.template import Library
|
||||||
from django.template.loader import get_template
|
from django.template.loader import get_template
|
||||||
|
from django.templatetags.static import static
|
||||||
from django.utils import formats
|
from django.utils import formats
|
||||||
from django.utils.deprecation import RemovedInDjango20Warning
|
from django.utils.deprecation import RemovedInDjango20Warning
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
|
|
|
@ -1,17 +1,11 @@
|
||||||
from django.apps import apps
|
|
||||||
from django.template import Library
|
from django.template import Library
|
||||||
|
from django.templatetags.static import static as _static
|
||||||
|
|
||||||
register = Library()
|
register = Library()
|
||||||
|
|
||||||
_static = None
|
|
||||||
|
|
||||||
|
|
||||||
@register.simple_tag
|
@register.simple_tag
|
||||||
def static(path):
|
def static(path):
|
||||||
global _static
|
# Backwards compatibility alias for django.templatetags.static.static().
|
||||||
if _static is None:
|
# Deprecation should start in Django 2.0.
|
||||||
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
|
|
||||||
return _static(path)
|
return _static(path)
|
||||||
|
|
|
@ -6,7 +6,6 @@ from __future__ import unicode_literals
|
||||||
import copy
|
import copy
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib.admin.templatetags.admin_static import static
|
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.db.models.deletion import CASCADE
|
from django.db.models.deletion import CASCADE
|
||||||
from django.forms.utils import flatatt
|
from django.forms.utils import flatatt
|
||||||
|
@ -32,7 +31,7 @@ class FilteredSelectMultiple(forms.SelectMultiple):
|
||||||
@property
|
@property
|
||||||
def media(self):
|
def media(self):
|
||||||
js = ["core.js", "SelectBox.js", "SelectFilter2.js"]
|
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=()):
|
def __init__(self, verbose_name, is_stacked, attrs=None, choices=()):
|
||||||
self.verbose_name = verbose_name
|
self.verbose_name = verbose_name
|
||||||
|
@ -56,7 +55,7 @@ class AdminDateWidget(forms.DateInput):
|
||||||
@property
|
@property
|
||||||
def media(self):
|
def media(self):
|
||||||
js = ["calendar.js", "admin/DateTimeShortcuts.js"]
|
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):
|
def __init__(self, attrs=None, format=None):
|
||||||
final_attrs = {'class': 'vDateField', 'size': '10'}
|
final_attrs = {'class': 'vDateField', 'size': '10'}
|
||||||
|
@ -69,7 +68,7 @@ class AdminTimeWidget(forms.TimeInput):
|
||||||
@property
|
@property
|
||||||
def media(self):
|
def media(self):
|
||||||
js = ["calendar.js", "admin/DateTimeShortcuts.js"]
|
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):
|
def __init__(self, attrs=None, format=None):
|
||||||
final_attrs = {'class': 'vTimeField', 'size': '8'}
|
final_attrs = {'class': 'vTimeField', 'size': '8'}
|
||||||
|
|
|
@ -1,36 +1,19 @@
|
||||||
from django import template
|
from django import template
|
||||||
from django.contrib.staticfiles.storage import staticfiles_storage
|
from django.templatetags.static import (
|
||||||
from django.templatetags.static import StaticNode
|
do_static as _do_static, static as _static,
|
||||||
|
)
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
|
||||||
|
|
||||||
def static(path):
|
def static(path):
|
||||||
return staticfiles_storage.url(path)
|
# Backwards compatibility alias for django.templatetags.static.static().
|
||||||
|
# Deprecation should start in Django 2.0.
|
||||||
|
return _static(path)
|
||||||
class StaticFilesNode(StaticNode):
|
|
||||||
|
|
||||||
def url(self, context):
|
|
||||||
path = self.path.resolve(context)
|
|
||||||
return static(path)
|
|
||||||
|
|
||||||
|
|
||||||
@register.tag('static')
|
@register.tag('static')
|
||||||
def do_static(parser, token):
|
def do_static(parser, token):
|
||||||
"""
|
# Backwards compatibility alias for django.templatetags.static.do_static().
|
||||||
A template tag that returns the URL to a file
|
# Deprecation should start in Django 2.0.
|
||||||
using staticfiles' storage backend
|
return _do_static(parser, token)
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ from itertools import chain
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.forms.utils import flatatt, to_current_timezone
|
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 import datetime_safe, formats, six
|
||||||
from django.utils.datastructures import MultiValueDict
|
from django.utils.datastructures import MultiValueDict
|
||||||
from django.utils.dates import MONTHS
|
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.html import conditional_escape, format_html, html_safe
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.utils.six.moves import range
|
from django.utils.six.moves import range
|
||||||
from django.utils.six.moves.urllib.parse import urljoin
|
|
||||||
from django.utils.translation import ugettext_lazy
|
from django.utils.translation import ugettext_lazy
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
|
@ -77,12 +77,15 @@ class Media(object):
|
||||||
) for path in self._css[medium]
|
) for path in self._css[medium]
|
||||||
] for medium in media])
|
] 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://', '/')):
|
if path.startswith(('http://', 'https://', '/')):
|
||||||
return path
|
return path
|
||||||
if prefix is None:
|
return static(path)
|
||||||
prefix = settings.STATIC_URL
|
|
||||||
return urljoin(prefix, path)
|
|
||||||
|
|
||||||
def __getitem__(self, name):
|
def __getitem__(self, name):
|
||||||
"Returns a Media object that only contains media of the given type"
|
"Returns a Media object that only contains media of the given type"
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from django import template
|
from django import template
|
||||||
|
from django.apps import apps
|
||||||
from django.utils.encoding import iri_to_uri
|
from django.utils.encoding import iri_to_uri
|
||||||
from django.utils.six.moves.urllib.parse import urljoin
|
from django.utils.six.moves.urllib.parse import urljoin
|
||||||
|
|
||||||
|
@ -108,6 +109,10 @@ class StaticNode(template.Node):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def handle_simple(cls, path):
|
def handle_simple(cls, 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)
|
return urljoin(PrefixNode.handle_simple("STATIC_URL"), path)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -151,4 +156,8 @@ def do_static(parser, token):
|
||||||
|
|
||||||
|
|
||||||
def static(path):
|
def static(path):
|
||||||
|
"""
|
||||||
|
Given a relative path to a static asset, return the absolute path to the
|
||||||
|
asset.
|
||||||
|
"""
|
||||||
return StaticNode.handle_simple(path)
|
return StaticNode.handle_simple(path)
|
||||||
|
|
|
@ -19,17 +19,17 @@ Configuring static files
|
||||||
STATIC_URL = '/static/'
|
STATIC_URL = '/static/'
|
||||||
|
|
||||||
3. In your templates, either hardcode the url like
|
3. In your templates, either hardcode the url like
|
||||||
``/static/my_app/myexample.jpg`` or, preferably, use the
|
``/static/my_app/myexample.jpg`` or, preferably, use the :ttag:`static`
|
||||||
:ttag:`static<staticfiles-static>` template tag to build the URL for the given
|
template tag to build the URL for the given relative path by using the
|
||||||
relative path by using the configured :setting:`STATICFILES_STORAGE` storage
|
configured :setting:`STATICFILES_STORAGE` storage (this makes it much easier
|
||||||
(this makes it much easier when you want to switch to a content delivery
|
when you want to switch to a content delivery network (CDN) for serving
|
||||||
network (CDN) for serving static files).
|
static files).
|
||||||
|
|
||||||
.. _staticfiles-in-templates:
|
.. _staticfiles-in-templates:
|
||||||
|
|
||||||
.. code-block:: html+django
|
.. code-block:: html+django
|
||||||
|
|
||||||
{% load staticfiles %}
|
{% load static %}
|
||||||
<img src="{% static "my_app/myexample.jpg" %}" alt="My image"/>
|
<img src="{% static "my_app/myexample.jpg" %}" alt="My image"/>
|
||||||
|
|
||||||
4. Store your static files in a folder called ``static`` in your app. For
|
4. Store your static files in a folder called ``static`` in your app. For
|
||||||
|
|
|
@ -304,7 +304,7 @@ Here's what the "base.html" template, including the use of :doc:`static files
|
||||||
.. snippet:: html+django
|
.. snippet:: html+django
|
||||||
:filename: mysite/templates/base.html
|
:filename: mysite/templates/base.html
|
||||||
|
|
||||||
{% load staticfiles %}
|
{% load static %}
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>{% block title %}{% endblock %}</title>
|
<title>{% block title %}{% endblock %}</title>
|
||||||
|
|
|
@ -68,13 +68,11 @@ Next, add the following at the top of ``polls/templates/polls/index.html``:
|
||||||
.. snippet:: html+django
|
.. snippet:: html+django
|
||||||
:filename: polls/templates/polls/index.html
|
:filename: polls/templates/polls/index.html
|
||||||
|
|
||||||
{% load staticfiles %}
|
{% load static %}
|
||||||
|
|
||||||
<link rel="stylesheet" type="text/css" href="{% static 'polls/style.css' %}" />
|
<link rel="stylesheet" type="text/css" href="{% static 'polls/style.css' %}" />
|
||||||
|
|
||||||
``{% load staticfiles %}`` loads the :ttag:`{% static %} <staticfiles-static>`
|
The ``{% static %}`` template tag generates the absolute URL of static files.
|
||||||
template tag from the ``staticfiles`` template library. The ``{% static %}``
|
|
||||||
template tag generates the absolute URL of the static file.
|
|
||||||
|
|
||||||
That's all you need to do for development. Reload
|
That's all you need to do for development. Reload
|
||||||
``http://localhost:8000/polls/`` and you should see that the question links are
|
``http://localhost:8000/polls/`` and you should see that the question links are
|
||||||
|
|
|
@ -26,7 +26,7 @@ In your custom ``change_form.html`` template, extend the
|
||||||
.. code-block:: html+django
|
.. code-block:: html+django
|
||||||
|
|
||||||
{% extends 'admin/change_form.html' %}
|
{% extends 'admin/change_form.html' %}
|
||||||
{% load admin_static %}
|
{% load static %}
|
||||||
|
|
||||||
{% block admin_change_form_document_ready %}
|
{% block admin_change_form_document_ready %}
|
||||||
{{ block.super }}
|
{{ block.super }}
|
||||||
|
@ -65,7 +65,7 @@ namespace, just listen to the event triggered from there. For example:
|
||||||
.. code-block:: html+django
|
.. code-block:: html+django
|
||||||
|
|
||||||
{% extends 'admin/change_form.html' %}
|
{% extends 'admin/change_form.html' %}
|
||||||
{% load admin_static %}
|
{% load static %}
|
||||||
|
|
||||||
{% block admin_change_form_document_ready %}
|
{% block admin_change_form_document_ready %}
|
||||||
{{ block.super }}
|
{{ block.super }}
|
||||||
|
|
|
@ -285,11 +285,16 @@ following requirements are met:
|
||||||
* the :setting:`STATICFILES_STORAGE` setting is set to
|
* the :setting:`STATICFILES_STORAGE` setting is set to
|
||||||
``'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'``
|
``'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'``
|
||||||
* the :setting:`DEBUG` setting is set to ``False``
|
* 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
|
* you've collected all your static files by using the
|
||||||
:djadmin:`collectstatic` management command
|
: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
|
Since creating the MD5 hash can be a performance burden to your website
|
||||||
during runtime, ``staticfiles`` will automatically store the mapping with
|
during runtime, ``staticfiles`` will automatically store the mapping with
|
||||||
hashed names for all processed files in a file called ``staticfiles.json``.
|
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
|
simply specify a custom entry in the :setting:`CACHES` setting named
|
||||||
``'staticfiles'``. It falls back to using the ``'default'`` cache backend.
|
``'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
|
Finders Module
|
||||||
==============
|
==============
|
||||||
|
|
||||||
|
@ -390,8 +358,10 @@ files:
|
||||||
which adds :setting:`STATIC_URL` to every template context rendered
|
which adds :setting:`STATIC_URL` to every template context rendered
|
||||||
with :class:`~django.template.RequestContext` contexts.
|
with :class:`~django.template.RequestContext` contexts.
|
||||||
|
|
||||||
- The builtin template tag :ttag:`static` which takes a path and
|
- The builtin template tag :ttag:`static` which takes a path and urljoins it
|
||||||
urljoins it with the static prefix :setting:`STATIC_URL`.
|
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
|
- The builtin template tag :ttag:`get_static_prefix` which populates a
|
||||||
template variable with the static prefix :setting:`STATIC_URL` to be
|
template variable with the static prefix :setting:`STATIC_URL` to be
|
||||||
|
|
|
@ -2399,8 +2399,9 @@ static
|
||||||
""""""
|
""""""
|
||||||
|
|
||||||
To link to static files that are saved in :setting:`STATIC_ROOT` Django ships
|
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
|
with a :ttag:`static` template tag. If the :mod:`django.contrib.staticfiles`
|
||||||
using :class:`~django.template.RequestContext` or not. For example::
|
app is installed, the tag will serve files using ``url()`` method of the
|
||||||
|
storage specified by :setting:`STATICFILES_STORAGE`. For example::
|
||||||
|
|
||||||
{% load static %}
|
{% load static %}
|
||||||
<img src="{% static "images/hi.jpg" %}" alt="Hi!" />
|
<img src="{% static "images/hi.jpg" %}" alt="Hi!" />
|
||||||
|
@ -2418,18 +2419,16 @@ slightly different call::
|
||||||
{% static "images/hi.jpg" as myphoto %}
|
{% static "images/hi.jpg" as myphoto %}
|
||||||
<img src="{{ myphoto }}"></img>
|
<img src="{{ myphoto }}"></img>
|
||||||
|
|
||||||
.. note::
|
.. admonition:: Using Jinja2 templates?
|
||||||
|
|
||||||
The :mod:`staticfiles<django.contrib.staticfiles>` contrib app also ships
|
See :class:`~django.template.backends.jinja2.Jinja2` for information on
|
||||||
with a :ttag:`static template tag<staticfiles-static>` which uses
|
using the ``static`` tag with Jinja2.
|
||||||
``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>`::
|
|
||||||
|
|
||||||
{% load static from staticfiles %}
|
.. versionchanged:: 1.10
|
||||||
<img src="{% static "images/hi.jpg" %}" alt="Hi!" />
|
|
||||||
|
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
|
.. templatetag:: get_static_prefix
|
||||||
|
|
||||||
|
|
|
@ -127,7 +127,11 @@ Minor features
|
||||||
:mod:`django.contrib.staticfiles`
|
: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`
|
:mod:`django.contrib.syndication`
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -169,7 +173,8 @@ File Uploads
|
||||||
Forms
|
Forms
|
||||||
^^^^^
|
^^^^^
|
||||||
|
|
||||||
* ...
|
* Form and widget ``Media`` is now served using
|
||||||
|
:mod:`django.contrib.staticfiles` if installed.
|
||||||
|
|
||||||
Generic Views
|
Generic Views
|
||||||
^^^^^^^^^^^^^
|
^^^^^^^^^^^^^
|
||||||
|
|
|
@ -459,10 +459,10 @@ more details.
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
The :mod:`staticfiles<django.contrib.staticfiles>` contrib app has a new
|
The :mod:`staticfiles<django.contrib.staticfiles>` contrib app has a new
|
||||||
:ttag:`static<staticfiles-static>` template tag to refer to files saved with
|
``static`` template tag to refer to files saved with the
|
||||||
the :setting:`STATICFILES_STORAGE` storage backend. It uses the storage
|
:setting:`STATICFILES_STORAGE` storage backend. It uses the storage backend's
|
||||||
backend's ``url`` method and therefore supports advanced features such as
|
``url`` method and therefore supports advanced features such as :ref:`serving
|
||||||
:ref:`serving files from a cloud service<staticfiles-from-cdn>`.
|
files from a cloud service<staticfiles-from-cdn>`.
|
||||||
|
|
||||||
``CachedStaticFilesStorage`` storage backend
|
``CachedStaticFilesStorage`` storage backend
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
|
@ -203,12 +203,13 @@ Paths in asset definitions
|
||||||
Paths used to specify assets can be either relative or absolute. If a
|
Paths used to specify assets can be either relative or absolute. If a
|
||||||
path starts with ``/``, ``http://`` or ``https://``, it will be
|
path starts with ``/``, ``http://`` or ``https://``, it will be
|
||||||
interpreted as an absolute path, and left as-is. All other paths will
|
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
|
Whether or not you use :mod:`django.contrib.staticfiles`, the
|
||||||
:doc:`staticfiles app </ref/contrib/staticfiles>` two new settings were added
|
:setting:`STATIC_URL` and :setting:`STATIC_ROOT` settings are required to
|
||||||
to refer to "static files" (images, CSS, JavaScript, etc.) that are needed
|
render a complete web page.
|
||||||
to render a complete web page: :setting:`STATIC_URL` and :setting:`STATIC_ROOT`.
|
|
||||||
|
|
||||||
To find the appropriate prefix to use, Django will check if the
|
To find the appropriate prefix to use, Django will check if the
|
||||||
:setting:`STATIC_URL` setting is not ``None`` and automatically fall back
|
: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://static.example.com/animations.js"></script>
|
||||||
<script type="text/javascript" src="http://othersite.com/actions.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
|
``Media`` objects
|
||||||
-----------------
|
-----------------
|
||||||
|
|
|
@ -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>"""
|
||||||
|
)
|
Loading…
Reference in New Issue