Fixed #14693, #14709 -- Backwards incompatible change to rectify the confusion around the STATICFILES_URL and STATICFILES_ROOT settings.
* Two new global settings that will be used by -- **but are not limited to** -- the staticfiles app: STATIC_ROOT and STATIC_URL. * Moving the 'django.contrib.staticfiles.templatetags.staticfiles' template tag to the core ('django.templatetags.static') and renaming it to 'get_static_prefix'. * Moving the context processor 'django.contrib.staticfiles.context_processors.staticfiles' to the core ('django.core.context_processors.static') and renaming it to 'static'. * Paths in media definitions will use STATIC_URL as the prefix if the value is not None, and falls back to the previously used MEDIA_URL. Thanks again to the community for constructive criticism and Carl and Russ for sanity-inducing discussions on IRC. git-svn-id: http://code.djangoproject.com/svn/django/trunk@14592 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
9b45f6cd54
commit
33d8fcde8a
|
@ -195,9 +195,9 @@ TEMPLATE_CONTEXT_PROCESSORS = (
|
|||
'django.core.context_processors.debug',
|
||||
'django.core.context_processors.i18n',
|
||||
'django.core.context_processors.media',
|
||||
'django.core.context_processors.static',
|
||||
# 'django.core.context_processors.request',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
'django.contrib.staticfiles.context_processors.staticfiles',
|
||||
)
|
||||
|
||||
# Output to use in template system for invalid (e.g. misspelled) variables.
|
||||
|
@ -256,13 +256,21 @@ SECRET_KEY = ''
|
|||
DEFAULT_FILE_STORAGE = 'django.core.files.storage.FileSystemStorage'
|
||||
|
||||
# Absolute filesystem path to the directory that will hold user-uploaded files.
|
||||
# Example: "/home/media/media.lawrence.com/"
|
||||
# Example: "/home/media/media.lawrence.com/media/"
|
||||
MEDIA_ROOT = ''
|
||||
|
||||
# URL that handles the media served from MEDIA_ROOT.
|
||||
# Example: "http://media.lawrence.com"
|
||||
# Example: "http://media.lawrence.com/media/"
|
||||
MEDIA_URL = ''
|
||||
|
||||
# Absolute path to the directory that holds static files.
|
||||
# Example: "/home/media/media.lawrence.com/static/"
|
||||
STATIC_ROOT = ''
|
||||
|
||||
# URL that handles the static files served from STATIC_ROOT.
|
||||
# Example: "http://media.lawrence.com/static/"
|
||||
STATIC_URL = None
|
||||
|
||||
# List of upload handler classes to be applied in order.
|
||||
FILE_UPLOAD_HANDLERS = (
|
||||
'django.core.files.uploadhandler.MemoryFileUploadHandler',
|
||||
|
@ -552,14 +560,6 @@ FIXTURE_DIRS = ()
|
|||
# STATICFILES #
|
||||
###############
|
||||
|
||||
# Absolute path to the directory that holds media.
|
||||
# Example: "/home/media/media.lawrence.com/static/"
|
||||
STATICFILES_ROOT = ''
|
||||
|
||||
# URL that handles the static files served from STATICFILES_ROOT.
|
||||
# Example: "http://media.lawrence.com/static/"
|
||||
STATICFILES_URL = '/static/'
|
||||
|
||||
# A list of locations of additional static files
|
||||
STATICFILES_DIRS = ()
|
||||
|
||||
|
|
|
@ -49,16 +49,16 @@ MEDIA_ROOT = ''
|
|||
|
||||
# URL that handles the media served from MEDIA_ROOT. Make sure to use a
|
||||
# trailing slash if there is a path component (optional in other cases).
|
||||
# Examples: "http://media.lawrence.com", "http://example.com/media/"
|
||||
# Examples: "http://media.lawrence.com/media/", "http://example.com/media/"
|
||||
MEDIA_URL = ''
|
||||
|
||||
# Absolute path to the directory that holds media.
|
||||
# Absolute path to the directory that holds static files.
|
||||
# Example: "/home/media/media.lawrence.com/static/"
|
||||
STATICFILES_ROOT = ''
|
||||
STATIC_ROOT = ''
|
||||
|
||||
# URL that handles the static files served from STATICFILES_ROOT.
|
||||
# Example: "http://static.lawrence.com/", "http://example.com/static/"
|
||||
STATICFILES_URL = '/static/'
|
||||
# URL that handles the static files served from STATIC_ROOT.
|
||||
# Example: "http://media.lawrence.com/static/"
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
# URL prefix for admin media -- CSS, JavaScript and images.
|
||||
# Make sure to use a trailing slash.
|
||||
|
|
|
@ -1,15 +1,11 @@
|
|||
from django.template import Library
|
||||
from django.utils.encoding import iri_to_uri
|
||||
from django.templatetags.static import PrefixNode
|
||||
|
||||
register = Library()
|
||||
|
||||
@register.simple_tag
|
||||
def admin_media_prefix():
|
||||
"""
|
||||
Returns the string contained in the setting ADMIN_MEDIA_PREFIX.
|
||||
"""
|
||||
try:
|
||||
from django.conf import settings
|
||||
except ImportError:
|
||||
return ''
|
||||
return iri_to_uri(settings.ADMIN_MEDIA_PREFIX)
|
||||
admin_media_prefix = register.simple_tag(admin_media_prefix)
|
||||
return PrefixNode.handle_simple("ADMIN_MEDIA_PREFIX")
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
from django.conf import settings
|
||||
|
||||
def staticfiles(request):
|
||||
return {
|
||||
'STATICFILES_URL': settings.STATICFILES_URL,
|
||||
}
|
|
@ -10,46 +10,44 @@ from django.contrib.staticfiles.views import serve
|
|||
class StaticFilesHandler(WSGIHandler):
|
||||
"""
|
||||
WSGI middleware that intercepts calls to the static files directory, as
|
||||
defined by the STATICFILES_URL setting, and serves those files.
|
||||
defined by the STATIC_URL setting, and serves those files.
|
||||
"""
|
||||
def __init__(self, application, media_dir=None):
|
||||
def __init__(self, application, base_dir=None):
|
||||
self.application = application
|
||||
if media_dir:
|
||||
self.media_dir = media_dir
|
||||
if base_dir:
|
||||
self.base_dir = base_dir
|
||||
else:
|
||||
self.media_dir = self.get_media_dir()
|
||||
self.media_url = urlparse(self.get_media_url())
|
||||
if settings.DEBUG:
|
||||
utils.check_settings()
|
||||
self.base_dir = self.get_base_dir()
|
||||
self.base_url = urlparse(self.get_base_url())
|
||||
super(StaticFilesHandler, self).__init__()
|
||||
|
||||
def get_media_dir(self):
|
||||
return settings.STATICFILES_ROOT
|
||||
def get_base_dir(self):
|
||||
return settings.STATIC_ROOT
|
||||
|
||||
def get_media_url(self):
|
||||
return settings.STATICFILES_URL
|
||||
def get_base_url(self):
|
||||
if settings.DEBUG:
|
||||
utils.check_settings()
|
||||
return settings.STATIC_URL
|
||||
|
||||
def _should_handle(self, path):
|
||||
"""
|
||||
Checks if the path should be handled. Ignores the path if:
|
||||
|
||||
* the host is provided as part of the media_url
|
||||
* the host is provided as part of the base_url
|
||||
* the request's path isn't under the media path (or equal)
|
||||
* settings.DEBUG isn't True
|
||||
"""
|
||||
return (self.media_url[2] != path and
|
||||
path.startswith(self.media_url[2]) and not self.media_url[1])
|
||||
return (self.base_url[2] != path and
|
||||
path.startswith(self.base_url[2]) and not self.base_url[1])
|
||||
|
||||
def file_path(self, url):
|
||||
"""
|
||||
Returns the relative path to the media file on disk for the given URL.
|
||||
|
||||
The passed URL is assumed to begin with ``media_url``. If the
|
||||
The passed URL is assumed to begin with ``base_url``. If the
|
||||
resultant file path is outside the media directory, then a ValueError
|
||||
is raised.
|
||||
"""
|
||||
# Remove ``media_url``.
|
||||
relative_url = url[len(self.media_url[2]):]
|
||||
relative_url = url[len(self.base_url[2]):]
|
||||
return urllib.url2pathname(relative_url)
|
||||
|
||||
def serve(self, request):
|
||||
|
|
|
@ -12,7 +12,7 @@ from django.contrib.staticfiles import finders
|
|||
class Command(NoArgsCommand):
|
||||
"""
|
||||
Command that allows to copy or symlink media files from different
|
||||
locations to the settings.STATICFILES_ROOT.
|
||||
locations to the settings.STATIC_ROOT.
|
||||
"""
|
||||
option_list = NoArgsCommand.option_list + (
|
||||
make_option('--noinput', action='store_false', dest='interactive',
|
||||
|
@ -85,7 +85,7 @@ Type 'yes' to continue, or 'no' to cancel: """)
|
|||
self.stdout.write("\n%s static file%s %s to '%s'%s.\n"
|
||||
% (actual_count, actual_count != 1 and 's' or '',
|
||||
symlink and 'symlinked' or 'copied',
|
||||
settings.STATICFILES_ROOT,
|
||||
settings.STATIC_ROOT,
|
||||
unmodified_count and ' (%s unmodified)'
|
||||
% unmodified_count or ''))
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ from django.contrib.staticfiles.handlers import StaticFilesHandler
|
|||
class Command(BaseRunserverCommand):
|
||||
option_list = BaseRunserverCommand.option_list + (
|
||||
make_option('--nostatic', action="store_false", dest='use_static_handler', default=True,
|
||||
help='Tells Django to NOT automatically serve static files at STATICFILES_URL.'),
|
||||
help='Tells Django to NOT automatically serve static files at STATIC_URL.'),
|
||||
make_option('--insecure', action="store_true", dest='insecure_serving', default=False,
|
||||
help='Allows serving static files even if DEBUG is False.'),
|
||||
)
|
||||
|
|
|
@ -12,21 +12,22 @@ class StaticFilesStorage(FileSystemStorage):
|
|||
Standard file system storage for site media files.
|
||||
|
||||
The defaults for ``location`` and ``base_url`` are
|
||||
``STATICFILES_ROOT`` and ``STATICFILES_URL``.
|
||||
``STATIC_ROOT`` and ``STATIC_URL``.
|
||||
"""
|
||||
def __init__(self, location=None, base_url=None, *args, **kwargs):
|
||||
if location is None:
|
||||
location = settings.STATICFILES_ROOT
|
||||
location = settings.STATIC_ROOT
|
||||
if base_url is None:
|
||||
base_url = settings.STATICFILES_URL
|
||||
base_url = settings.STATIC_URL
|
||||
if not location:
|
||||
raise ImproperlyConfigured("You're using the staticfiles app "
|
||||
"without having set the STATICFILES_ROOT setting. Set it to "
|
||||
"without having set the STATIC_ROOT setting. Set it to "
|
||||
"the absolute path of the directory that holds static media.")
|
||||
if not base_url:
|
||||
# check for None since we might use a root URL (``/``)
|
||||
if base_url is None:
|
||||
raise ImproperlyConfigured("You're using the staticfiles app "
|
||||
"without having set the STATICFILES_URL setting. Set it to "
|
||||
"URL that handles the files served from STATICFILES_ROOT.")
|
||||
"without having set the STATIC_URL setting. Set it to "
|
||||
"URL that handles the files served from STATIC_ROOT.")
|
||||
if settings.DEBUG:
|
||||
utils.check_settings()
|
||||
super(StaticFilesStorage, self).__init__(location, base_url, *args, **kwargs)
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
from django import template
|
||||
from django.utils.encoding import iri_to_uri
|
||||
|
||||
register = template.Library()
|
||||
|
||||
class StaticFilesPrefixNode(template.Node):
|
||||
|
||||
def __init__(self, varname=None):
|
||||
self.varname = varname
|
||||
|
||||
def render(self, context):
|
||||
try:
|
||||
from django.conf import settings
|
||||
except ImportError:
|
||||
prefix = ''
|
||||
else:
|
||||
prefix = iri_to_uri(settings.STATICFILES_URL)
|
||||
if self.varname is None:
|
||||
return prefix
|
||||
context[self.varname] = prefix
|
||||
return ''
|
||||
|
||||
@register.tag
|
||||
def get_staticfiles_prefix(parser, token):
|
||||
"""
|
||||
Populates a template variable with the prefix (settings.STATICFILES_URL).
|
||||
|
||||
Usage::
|
||||
|
||||
{% get_staticfiles_prefix [as varname] %}
|
||||
|
||||
Examples::
|
||||
|
||||
{% get_staticfiles_prefix %}
|
||||
{% get_staticfiles_prefix as staticfiles_prefix %}
|
||||
|
||||
"""
|
||||
tokens = token.contents.split()
|
||||
if len(tokens) > 1 and tokens[1] != 'as':
|
||||
raise template.TemplateSyntaxError(
|
||||
"First argument in '%s' must be 'as'" % tokens[0])
|
||||
return StaticFilesPrefixNode(varname=(len(tokens) > 1 and tokens[2] or None))
|
||||
|
|
@ -18,15 +18,10 @@ def staticfiles_urlpatterns(prefix=None):
|
|||
if not settings.DEBUG:
|
||||
return []
|
||||
if prefix is None:
|
||||
prefix = settings.STATICFILES_URL
|
||||
if not prefix:
|
||||
prefix = settings.STATIC_URL
|
||||
if not prefix or '://' in prefix:
|
||||
raise ImproperlyConfigured(
|
||||
"The prefix for the 'staticfiles_urlpatterns' helper is empty. "
|
||||
"Make sure the STATICFILES_URL setting is set correctly.")
|
||||
if '://' in prefix:
|
||||
raise ImproperlyConfigured(
|
||||
"The STATICFILES_URL setting is a full URL, not a path and "
|
||||
"can't be used with the 'staticfiles_urlpatterns' helper.")
|
||||
"The prefix for the 'staticfiles_urlpatterns' helper is invalid.")
|
||||
if prefix.startswith("/"):
|
||||
prefix = prefix[1:]
|
||||
return patterns('',
|
||||
|
|
|
@ -33,13 +33,13 @@ def get_files(storage, ignore_patterns=[], location=''):
|
|||
|
||||
def check_settings():
|
||||
"""
|
||||
Checks if the MEDIA_(ROOT|URL) and STATICFILES_(ROOT|URL)
|
||||
Checks if the MEDIA_(ROOT|URL) and STATIC_(ROOT|URL)
|
||||
settings have the same value.
|
||||
"""
|
||||
if settings.MEDIA_URL == settings.STATICFILES_URL:
|
||||
raise ImproperlyConfigured("The MEDIA_URL and STATICFILES_URL "
|
||||
"settings must have individual values")
|
||||
if ((settings.MEDIA_ROOT and settings.STATICFILES_ROOT) and
|
||||
(settings.MEDIA_ROOT == settings.STATICFILES_ROOT)):
|
||||
raise ImproperlyConfigured("The MEDIA_ROOT and STATICFILES_ROOT "
|
||||
"settings must have individual values")
|
||||
if settings.MEDIA_URL == settings.STATIC_URL:
|
||||
raise ImproperlyConfigured("The MEDIA_URL and STATIC_URL "
|
||||
"settings must have different values")
|
||||
if ((settings.MEDIA_ROOT and settings.STATIC_ROOT) and
|
||||
(settings.MEDIA_ROOT == settings.STATIC_ROOT)):
|
||||
raise ImproperlyConfigured("The MEDIA_ROOT and STATIC_ROOT "
|
||||
"settings must have different values")
|
||||
|
|
|
@ -66,6 +66,13 @@ def i18n(request):
|
|||
|
||||
return context_extras
|
||||
|
||||
def static(request):
|
||||
"""
|
||||
Adds static-related context variables to the context.
|
||||
|
||||
"""
|
||||
return {'STATIC_URL': settings.STATIC_URL}
|
||||
|
||||
def media(request):
|
||||
"""
|
||||
Adds media-related context variables to the context.
|
||||
|
|
|
@ -17,8 +17,8 @@ import warnings
|
|||
from django.core.management.color import color_style
|
||||
from django.utils.http import http_date
|
||||
from django.utils._os import safe_join
|
||||
from django.contrib.staticfiles.handlers import StaticFilesHandler
|
||||
from django.views import static
|
||||
|
||||
from django.contrib.staticfiles import handlers, views as static
|
||||
|
||||
__version__ = "0.1"
|
||||
__all__ = ['WSGIServer','WSGIRequestHandler']
|
||||
|
@ -635,19 +635,20 @@ class WSGIRequestHandler(BaseHTTPRequestHandler):
|
|||
sys.stderr.write(msg)
|
||||
|
||||
|
||||
class AdminMediaHandler(StaticFilesHandler):
|
||||
class AdminMediaHandler(handlers.StaticFilesHandler):
|
||||
"""
|
||||
WSGI middleware that intercepts calls to the admin media directory, as
|
||||
defined by the ADMIN_MEDIA_PREFIX setting, and serves those images.
|
||||
Use this ONLY LOCALLY, for development! This hasn't been tested for
|
||||
security and is not super efficient.
|
||||
"""
|
||||
|
||||
def get_media_dir(self):
|
||||
This is pending for deprecation since 1.3.
|
||||
"""
|
||||
def get_base_dir(self):
|
||||
import django
|
||||
return os.path.join(django.__path__[0], 'contrib', 'admin', 'media')
|
||||
|
||||
def get_media_url(self):
|
||||
def get_base_url(self):
|
||||
from django.conf import settings
|
||||
return settings.ADMIN_MEDIA_PREFIX
|
||||
|
||||
|
@ -655,14 +656,13 @@ class AdminMediaHandler(StaticFilesHandler):
|
|||
"""
|
||||
Returns the path to the media file on disk for the given URL.
|
||||
|
||||
The passed URL is assumed to begin with ``media_url``. If the
|
||||
resultant file path is outside the media directory, then a ValueError
|
||||
The passed URL is assumed to begin with ``self.base_url``. If the
|
||||
resulting file path is outside the media directory, then a ValueError
|
||||
is raised.
|
||||
"""
|
||||
# Remove ``media_url``.
|
||||
relative_url = url[len(self.media_url[2]):]
|
||||
relative_url = url[len(self.base_url[2]):]
|
||||
relative_path = urllib.url2pathname(relative_url)
|
||||
return safe_join(self.media_dir, relative_path)
|
||||
return safe_join(self.base_dir, relative_path)
|
||||
|
||||
def serve(self, request):
|
||||
document_root, path = os.path.split(self.file_path(request.path))
|
||||
|
@ -673,10 +673,10 @@ class AdminMediaHandler(StaticFilesHandler):
|
|||
"""
|
||||
Checks if the path should be handled. Ignores the path if:
|
||||
|
||||
* the host is provided as part of the media_url
|
||||
* the request's path isn't under the media path
|
||||
* the host is provided as part of the base_url
|
||||
* the request's path isn't under the base path
|
||||
"""
|
||||
return path.startswith(self.media_url[2]) and not self.media_url[1]
|
||||
return path.startswith(self.base_url[2]) and not self.base_url[1]
|
||||
|
||||
|
||||
def run(addr, port, wsgi_handler):
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
"""
|
||||
HTML Widget classes
|
||||
"""
|
||||
import datetime
|
||||
from itertools import chain
|
||||
import time
|
||||
from urlparse import urljoin
|
||||
from util import flatatt
|
||||
|
||||
import django.utils.copycompat as copy
|
||||
from itertools import chain
|
||||
from django.conf import settings
|
||||
from django.utils.datastructures import MultiValueDict, MergeDict
|
||||
from django.utils.html import escape, conditional_escape
|
||||
|
@ -11,10 +15,6 @@ from django.utils.translation import ugettext, ugettext_lazy
|
|||
from django.utils.encoding import StrAndUnicode, force_unicode
|
||||
from django.utils.safestring import mark_safe
|
||||
from django.utils import datetime_safe, formats
|
||||
import time
|
||||
import datetime
|
||||
from util import flatatt
|
||||
from urlparse import urljoin
|
||||
|
||||
__all__ = (
|
||||
'Media', 'MediaDefiningClass', 'Widget', 'TextInput', 'PasswordInput',
|
||||
|
@ -63,10 +63,16 @@ class Media(StrAndUnicode):
|
|||
for path in self._css[medium]]
|
||||
for medium in media])
|
||||
|
||||
def absolute_path(self, path):
|
||||
def absolute_path(self, path, prefix=None):
|
||||
if path.startswith(u'http://') or path.startswith(u'https://') or path.startswith(u'/'):
|
||||
return path
|
||||
return urljoin(settings.MEDIA_URL,path)
|
||||
if prefix is None:
|
||||
if settings.STATIC_URL is None:
|
||||
# backwards compatibility
|
||||
prefix = settings.MEDIA_URL
|
||||
else:
|
||||
prefix = settings.STATIC_URL
|
||||
return urljoin(prefix, path)
|
||||
|
||||
def __getitem__(self, name):
|
||||
"Returns a Media object that only contains media of the given type"
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
from django import template
|
||||
from django.utils.encoding import iri_to_uri
|
||||
|
||||
register = template.Library()
|
||||
|
||||
class PrefixNode(template.Node):
|
||||
|
||||
def __repr__(self):
|
||||
return "<PrefixNode for %r>" % self.name
|
||||
|
||||
def __init__(self, varname=None, name=None):
|
||||
if name is None:
|
||||
raise template.TemplateSyntaxError(
|
||||
"Prefix nodes must be given a name to return.")
|
||||
self.varname = varname
|
||||
self.name = name
|
||||
|
||||
@classmethod
|
||||
def handle_token(cls, parser, token, name):
|
||||
"""
|
||||
Class method to parse prefix node and return a Node.
|
||||
"""
|
||||
tokens = token.contents.split()
|
||||
if len(tokens) > 1 and tokens[1] != 'as':
|
||||
raise template.TemplateSyntaxError(
|
||||
"First argument in '%s' must be 'as'" % tokens[0])
|
||||
if len(tokens) > 1:
|
||||
varname = tokens[2]
|
||||
else:
|
||||
varname = None
|
||||
return cls(varname, name)
|
||||
|
||||
@classmethod
|
||||
def handle_simple(cls, name):
|
||||
try:
|
||||
from django.conf import settings
|
||||
except ImportError:
|
||||
prefix = ''
|
||||
else:
|
||||
prefix = iri_to_uri(getattr(settings, name, ''))
|
||||
return prefix
|
||||
|
||||
def render(self, context):
|
||||
prefix = self.handle_simple(self.name)
|
||||
if self.varname is None:
|
||||
return prefix
|
||||
context[self.varname] = prefix
|
||||
return ''
|
||||
|
||||
@register.tag
|
||||
def get_static_prefix(parser, token):
|
||||
"""
|
||||
Populates a template variable with the static prefix,
|
||||
``settings.STATIC_URL``.
|
||||
|
||||
Usage::
|
||||
|
||||
{% get_static_prefix [as varname] %}
|
||||
|
||||
Examples::
|
||||
|
||||
{% get_static_prefix %}
|
||||
{% get_static_prefix as static_prefix %}
|
||||
|
||||
"""
|
||||
return PrefixNode.handle_token(parser, token, "STATIC_URL")
|
||||
|
||||
@register.tag
|
||||
def get_media_prefix(parser, token):
|
||||
"""
|
||||
Populates a template variable with the static prefix,
|
||||
``settings.MEDIA_URL``.
|
||||
|
||||
Usage::
|
||||
|
||||
{% get_media_prefix [as varname] %}
|
||||
|
||||
Examples::
|
||||
|
||||
{% get_media_prefix %}
|
||||
{% get_media_prefix as media_prefix %}
|
||||
|
||||
"""
|
||||
return PrefixNode.handle_token(parser, token, "MEDIA_URL")
|
|
@ -17,8 +17,8 @@ from django.http import Http404, HttpResponse, HttpResponseRedirect, HttpRespons
|
|||
from django.template import Template, Context, TemplateDoesNotExist
|
||||
from django.utils.http import http_date
|
||||
|
||||
from django.contrib.staticfiles.views import \
|
||||
directory_index, was_modified_since, serve as staticfiles_serve
|
||||
from django.contrib.staticfiles.views import (directory_index,
|
||||
was_modified_since, serve as staticfiles_serve)
|
||||
|
||||
|
||||
def serve(request, path, document_root=None, show_indexes=False, insecure=False):
|
||||
|
|
|
@ -50,12 +50,12 @@ Here's the basic usage in a nutshell:
|
|||
First, you'll need to make sure that ``django.contrib.staticfiles`` is in
|
||||
your :setting:`INSTALLED_APPS`.
|
||||
|
||||
Next, you'll need to edit :setting:`STATICFILES_ROOT` to point to where
|
||||
Next, you'll need to edit :setting:`STATIC_ROOT` to point to where
|
||||
you'd like your static media stored. For example::
|
||||
|
||||
STATICFILES_ROOT = "/home/jacob/projects/mysite.com/static_media"
|
||||
STATIC_ROOT = "/home/jacob/projects/mysite.com/static_media"
|
||||
|
||||
You may also want to set the :setting:`STATICFILES_URL` setting at this
|
||||
You may also want to set the :setting:`STATIC_URL` setting at this
|
||||
time, though the default value (of ``/static/``) is perfect for local
|
||||
development.
|
||||
|
||||
|
@ -69,7 +69,7 @@ Here's the basic usage in a nutshell:
|
|||
./manage.py collectstatic
|
||||
|
||||
This'll churn through your static file storage and move them into the
|
||||
directory given by :setting:`STATICFILES_ROOT`. (This is not necessary
|
||||
directory given by :setting:`STATIC_ROOT`. (This is not necessary
|
||||
in local development if you are using :djadmin:`runserver` or adding
|
||||
``staticfiles_urlpatterns`` to your URLconf; see below).
|
||||
|
||||
|
@ -78,7 +78,7 @@ Here's the basic usage in a nutshell:
|
|||
If you're using the built-in development server (the
|
||||
:djadmin:`runserver` management command) and have the :setting:`DEBUG`
|
||||
setting set to ``True``, your staticfiles will automatically be served
|
||||
from :setting:`STATICFILES_URL` in development.
|
||||
from :setting:`STATIC_URL` in development.
|
||||
|
||||
If you are using some other server for local development, you can
|
||||
quickly serve static media locally by adding::
|
||||
|
@ -98,7 +98,7 @@ Here's the basic usage in a nutshell:
|
|||
|
||||
.. code-block:: html+django
|
||||
|
||||
<img src="{{ STATICFILES_URL }}images/hi.jpg />
|
||||
<img src="{{ STATIC_URL }}images/hi.jpg />
|
||||
|
||||
See :ref:`staticfiles-in-templates` for more details, including an
|
||||
alternate method (using a template tag).
|
||||
|
@ -115,7 +115,7 @@ the framework see :doc:`the staticfiles reference </ref/contrib/staticfiles>`.
|
|||
app is to make it easier to keep static files separate from user-uploaded
|
||||
files. For this reason, you will probably want to make your
|
||||
:setting:`MEDIA_ROOT` and :setting:`MEDIA_URL` different from your
|
||||
:setting:`STATICFILES_ROOT` and :setting:`STATICFILES_URL`. You will need to
|
||||
:setting:`STATIC_ROOT` and :setting:`STATIC_URL`. You will need to
|
||||
arrange for serving of files in :setting:`MEDIA_ROOT` yourself;
|
||||
``staticfiles`` does not deal with user-uploaded media at all.
|
||||
|
||||
|
@ -136,7 +136,7 @@ development, and it makes it *very* hard to change where you've deployed your
|
|||
media. If, for example, you wanted to switch to using a content delivery network
|
||||
(CDN), then you'd need to change more or less every single template.
|
||||
|
||||
A far better way is to use the value of the :setting:`STATICFILES_URL` setting
|
||||
A far better way is to use the value of the :setting:`STATIC_URL` setting
|
||||
directly in your templates. This means that a switch of media servers only
|
||||
requires changing that single value. Much better!
|
||||
|
||||
|
@ -147,7 +147,7 @@ With a context processor
|
|||
------------------------
|
||||
|
||||
The included context processor is the easy way. Simply make sure
|
||||
``'django.contrib.staticfiles.context_processors.staticfiles'`` is in your
|
||||
``'django.core.context_processors.static'`` is in your
|
||||
:setting:`TEMPLATE_CONTEXT_PROCESSORS`. It's there by default, and if you're
|
||||
editing that setting by hand it should look something like::
|
||||
|
||||
|
@ -155,18 +155,18 @@ editing that setting by hand it should look something like::
|
|||
'django.core.context_processors.debug',
|
||||
'django.core.context_processors.i18n',
|
||||
'django.core.context_processors.media',
|
||||
'django.core.context_processors.static',
|
||||
'django.contrib.auth.context_processors.auth',
|
||||
'django.contrib.messages.context_processors.messages',
|
||||
'django.contrib.staticfiles.context_processors.staticfiles',
|
||||
)
|
||||
|
||||
Once that's done, you can refer to :setting:`STATICFILES_URL` in your templates:
|
||||
Once that's done, you can refer to :setting:`STATIC_URL` in your templates:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
<img src="{{ STATICFILES_URL }}images/hi.jpg />
|
||||
<img src="{{ STATIC_URL }}images/hi.jpg />
|
||||
|
||||
If ``{{ STATICFILES_URL }}`` isn't working in your template, you're probably not
|
||||
If ``{{ STATIC_URL }}`` isn't working in your template, you're probably not
|
||||
using :class:`~django.template.RequestContext` when rendering the template.
|
||||
|
||||
As a brief refresher, context processors add variables into the contexts of
|
||||
|
@ -180,23 +180,23 @@ To see how that works, and to read more details, check out
|
|||
With a template tag
|
||||
-------------------
|
||||
|
||||
The second option is the :ttag:`get_staticfiles_prefix` template tag. You can
|
||||
The second option is the :ttag:`get_static_prefix` template tag. You can
|
||||
use this if you're not using :class:`~django.template.RequestContext`, or if you
|
||||
need more control over exactly where and how :setting:`STATICFILES_URL` is
|
||||
need more control over exactly where and how :setting:`STATIC_URL` is
|
||||
injected into the template. Here's an example:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
{% load staticfiles %}
|
||||
<img src="{% get_staticfiles_prefix %}images/hi.jpg" />
|
||||
{% load static %}
|
||||
<img src="{% get_static_prefix %}images/hi.jpg" />
|
||||
|
||||
There's also a second form you can use to avoid extra processing if you need the
|
||||
value multiple times:
|
||||
|
||||
.. code-block:: html+django
|
||||
|
||||
{% load staticfiles %}
|
||||
{% get_staticfiles_prefix as STATIC_PREFIX %}
|
||||
{% load static %}
|
||||
{% get_static_prefix as STATIC_PREFIX %}
|
||||
|
||||
<img src="{{ STATIC_PREFIX }}images/hi.jpg" />
|
||||
<img src="{{ STATIC_PREFIX }}images/hi2.jpg" />
|
||||
|
@ -213,7 +213,7 @@ Thus, the ``staticfiles`` app ships with a quick and dirty helper view that you
|
|||
can use to serve files locally in development.
|
||||
|
||||
This view is automatically enabled and will serve your static files at
|
||||
:setting:`STATICFILES_URL` when you use the built-in :djadmin:`runserver`.
|
||||
:setting:`STATIC_URL` when you use the built-in :djadmin:`runserver`.
|
||||
|
||||
To enable this view if you are using some other server for local development,
|
||||
you'll add a couple of lines to your URLconf. The first line goes at the top of
|
||||
|
@ -225,11 +225,11 @@ the file, and the last line at the bottom::
|
|||
|
||||
urlpatterns += staticfiles_urlpatterns()
|
||||
|
||||
This will inspect your :setting:`STATICFILES_URL` and
|
||||
:setting:`STATICFILES_ROOT` settings and wire up the view to serve static media
|
||||
This will inspect your :setting:`STATIC_URL` and
|
||||
:setting:`STATIC_ROOT` settings and wire up the view to serve static media
|
||||
accordingly. Don't forget to set the :setting:`STATICFILES_DIRS` setting
|
||||
appropriately to let ``django.contrib.staticfiles`` know where to look for
|
||||
files.
|
||||
(additional) files.
|
||||
|
||||
.. warning::
|
||||
|
||||
|
@ -239,6 +239,9 @@ files.
|
|||
**insecure**. This is only intended for local development, and should
|
||||
**never be used in production**.
|
||||
|
||||
Additionally, your :setting:`STATIC_URL` setting can't be either empty
|
||||
or a full URL such as ``http://static.example.com/``.
|
||||
|
||||
For a few more details, including an alternate method of enabling this view,
|
||||
see :ref:`staticfiles-development-view`.
|
||||
|
||||
|
@ -249,7 +252,7 @@ Serving static files in production
|
|||
|
||||
The basic outline of putting static files into production is simple: run the
|
||||
:djadmin:`collectstatic` command when static media changes, then arrange for the
|
||||
collected media directory (:setting:`STATICFILES_ROOT`) to be moved to the media
|
||||
collected media directory (:setting:`STATIC_ROOT`) to be moved to the media
|
||||
server and served.
|
||||
|
||||
Of course, as with all deployment tasks, the devil's in the details. Every
|
||||
|
@ -264,8 +267,8 @@ app, the basic outline gets modified to look something like:
|
|||
|
||||
* Push your code up to the deployment server.
|
||||
* On the server, run :djadmin:`collectstatic` to move all the media into
|
||||
:setting:`STATICFILES_ROOT`.
|
||||
* Point your web server at :setting:`STATICFILES_ROOT`. For example, here's
|
||||
:setting:`STATIC_ROOT`.
|
||||
* Point your web server at :setting:`STATIC_ROOT`. For example, here's
|
||||
:ref:`how to do this under Apache and mod_wsgi <serving-media-files>`.
|
||||
|
||||
You'll probably want to automate this process, especially if you've got multiple
|
||||
|
@ -322,7 +325,7 @@ Since your media server won't be running Django, you'll need to modify the
|
|||
deployment strategy to look something like:
|
||||
|
||||
* When your media changes, run :djadmin:`collectstatic` locally.
|
||||
* Push your local :setting:`STATICFILES_ROOT` up to the media server
|
||||
* Push your local :setting:`STATIC_ROOT` up to the media server
|
||||
into the directory that's being served. ``rsync`` is a good
|
||||
choice for this step since it only needs to transfer the
|
||||
bits of static media that have changed.
|
||||
|
@ -403,9 +406,6 @@ you'll need to make a few changes:
|
|||
* The management commands ``build_static`` and ``resolve_static`` are now
|
||||
called :djadmin:`collectstatic` and :djadmin:`findstatic`.
|
||||
|
||||
* The settings ``STATIC_URL`` and ``STATIC_ROOT`` were renamed to
|
||||
:setting:`STATICFILES_URL` and :setting:`STATICFILES_ROOT`.
|
||||
|
||||
* The settings ``STATICFILES_PREPEND_LABEL_APPS``,
|
||||
``STATICFILES_MEDIA_DIRNAMES`` and ``STATICFILES_EXCLUDED_APPS`` were
|
||||
removed.
|
||||
|
|
|
@ -165,7 +165,7 @@ Do not prompt the user for input.
|
|||
Disable the development server's auto\-reloader.
|
||||
.TP
|
||||
.I \-\-nostatic
|
||||
Disable automatic serving of static files from STATICFILES_URL.
|
||||
Disable automatic serving of static files from STATIC_URL.
|
||||
.TP
|
||||
.I \-\-insecure
|
||||
Enables serving of static files even if DEBUG is False.
|
||||
|
|
|
@ -23,48 +23,11 @@ Settings
|
|||
|
||||
.. highlight:: python
|
||||
|
||||
The following settings control the behavior of the staticfiles app. Only
|
||||
:setting:`STATICFILES_ROOT` is required, but you'll probably also need to
|
||||
configure :setting:`STATICFILES_URL` as well.
|
||||
.. note::
|
||||
|
||||
.. setting:: STATICFILES_ROOT
|
||||
|
||||
STATICFILES_ROOT
|
||||
----------------
|
||||
|
||||
Default: ``''`` (Empty string)
|
||||
|
||||
The absolute path to the directory that the :djadmin:`collectstatic` management
|
||||
command will collect static files into, for serving from
|
||||
:setting:`STATICFILES_URL`::
|
||||
|
||||
STATICFILES_ROOT = "/home/example.com/static/"
|
||||
|
||||
This is a **required setting** unless you've overridden
|
||||
:setting:`STATICFILES_STORAGE` and are using a custom storage backend.
|
||||
|
||||
This is not a place to store your static files permanently under version
|
||||
control; you should do that in directories that will be found by your
|
||||
:setting:`STATICFILES_FINDERS` (by default, per-app ``static/`` subdirectories,
|
||||
and any directories you include in :setting:`STATICFILES_DIRS`). Files from
|
||||
those locations will be collected into :setting:`STATICFILES_ROOT`.
|
||||
|
||||
.. setting:: STATICFILES_URL
|
||||
|
||||
STATICFILES_URL
|
||||
---------------
|
||||
|
||||
Default: ``'/static/'``
|
||||
|
||||
The URL that handles the files served from :setting:`STATICFILES_ROOT`, e.g.::
|
||||
|
||||
STATICFILES_URL = '/site_media/static/'
|
||||
|
||||
... or perhaps::
|
||||
|
||||
STATICFILES_URL = 'http://static.example.com/'
|
||||
|
||||
This should **always** have a trailing slash.
|
||||
The following settings control the behavior of the staticfiles app.
|
||||
Configuring the global settings :setting:`STATIC_ROOT` and
|
||||
:setting:`STATIC_URL` is **required**.
|
||||
|
||||
.. setting:: STATICFILES_DIRS
|
||||
|
||||
|
@ -98,7 +61,7 @@ tuples, e.g.::
|
|||
|
||||
With this configuration, the :djadmin:`collectstatic` management command would
|
||||
for example collect the stats files in a ``'downloads'`` directory. So
|
||||
assuming you have :setting:`STATICFILES_URL` set ``'/static/'``, this would
|
||||
assuming you have :setting:`STATIC_URL` set ``'/static/'``, this would
|
||||
allow you to refer to the file ``'/opt/webfiles/stats/polls_20101022.tar.gz'``
|
||||
with ``'/static/downloads/polls_20101022.tar.gz'`` in your templates.
|
||||
|
||||
|
@ -153,14 +116,14 @@ Management Commands
|
|||
|
||||
.. highlight:: console
|
||||
|
||||
``django.contrib.staticfiles`` exposes two management commands.
|
||||
``django.contrib.staticfiles`` exposes three management commands.
|
||||
|
||||
collectstatic
|
||||
-------------
|
||||
|
||||
.. django-admin:: collectstatic
|
||||
|
||||
Collects the static files into :setting:`STATICFILES_ROOT`.
|
||||
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
|
||||
|
@ -218,44 +181,76 @@ for each relative path, use the ``--first`` option::
|
|||
This is a debugging aid; it'll show you exactly which static file will be
|
||||
collected for a given path.
|
||||
|
||||
runserver
|
||||
---------
|
||||
|
||||
Overrides the core :djadmin:`runserver` command if the ``staticfiles`` app
|
||||
is :setting:`installed<INSTALLED_APPS>` and adds automatic serving of static
|
||||
files and the following new 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::
|
||||
|
||||
django-admin.py 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.
|
||||
|
||||
Example usage::
|
||||
|
||||
django-admin.py runserver --insecure
|
||||
|
||||
.. currentmodule:: None
|
||||
|
||||
Other Helpers
|
||||
=============
|
||||
|
||||
The ``staticfiles`` context processor
|
||||
-------------------------------------
|
||||
The ``static`` context processor
|
||||
--------------------------------
|
||||
|
||||
.. function:: django.contrib.staticfiles.context_processors.staticfiles
|
||||
.. function:: django.core.context_processors.static
|
||||
|
||||
This context processor adds the :setting:`STATICFILES_URL` into each template
|
||||
context as the variable ``{{ STATICFILES_URL }}``. To use it, make sure that
|
||||
``'django.contrib.staticfiles.context_processors.staticfiles'`` appears
|
||||
somewhere in your :setting:`TEMPLATE_CONTEXT_PROCESSORS` setting.
|
||||
This context processor adds the :setting:`STATIC_URL` into each template
|
||||
context as the variable ``{{ STATIC_URL }}``. To use it, make sure that
|
||||
``'django.core.context_processors.static'`` appears somewhere in your
|
||||
:setting:`TEMPLATE_CONTEXT_PROCESSORS` setting.
|
||||
|
||||
Remember, only templates rendered with :class:`~django.template.RequestContext`
|
||||
will have acces to the data provided by this (and any) context processor.
|
||||
|
||||
.. templatetag:: get_staticfiles_prefix
|
||||
.. templatetag:: get_static_prefix
|
||||
|
||||
The ``get_staticfiles_prefix`` templatetag
|
||||
==========================================
|
||||
The ``get_static_prefix`` templatetag
|
||||
=====================================
|
||||
|
||||
.. highlight:: html+django
|
||||
|
||||
If you're not using :class:`~django.template.RequestContext`, or if you need
|
||||
more control over exactly where and how :setting:`STATICFILES_URL` is injected
|
||||
into the template, you can use the :ttag:`get_staticfiles_prefix` template tag
|
||||
more control over exactly where and how :setting:`STATIC_URL` is injected
|
||||
into the template, you can use the :ttag:`get_static_prefix` template tag
|
||||
instead::
|
||||
|
||||
{% load staticfiles %}
|
||||
<img src="{% get_staticfiles_prefix %}images/hi.jpg" />
|
||||
{% load static %}
|
||||
<img src="{% get_static_prefix %}images/hi.jpg" />
|
||||
|
||||
There's also a second form you can use to avoid extra processing if you need
|
||||
the value multiple times::
|
||||
|
||||
{% load staticfiles %}
|
||||
{% get_staticfiles_prefix as STATIC_PREFIX %}
|
||||
{% load static %}
|
||||
{% get_static_prefix as STATIC_PREFIX %}
|
||||
|
||||
<img src="{{ STATIC_PREFIX }}images/hi.jpg" />
|
||||
<img src="{{ STATIC_PREFIX }}images/hi2.jpg" />
|
||||
|
@ -292,7 +287,7 @@ primary URL configuration::
|
|||
)
|
||||
|
||||
Note, the begin of the pattern (``r'^static/'``) should be your
|
||||
:setting:`STATICFILES_URL` setting.
|
||||
:setting:`STATIC_URL` setting.
|
||||
|
||||
Since this is a bit finicky, there's also a helper function that'll do this for you:
|
||||
|
||||
|
@ -307,3 +302,8 @@ already defined pattern list. Use it like this::
|
|||
|
||||
urlpatterns += staticfiles_urlpatterns()
|
||||
|
||||
.. 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/``.
|
||||
|
|
|
@ -681,35 +681,6 @@ Example usage::
|
|||
|
||||
django-admin.py runserver --noreload
|
||||
|
||||
.. 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::
|
||||
|
||||
django-admin.py 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.
|
||||
|
||||
See the :doc:`reference documentation of the app </ref/contrib/staticfiles>`
|
||||
for more details and learn how to :doc:`manage and deploy static files
|
||||
</howto/static-files>` correctly.
|
||||
|
||||
Example usage::
|
||||
|
||||
django-admin.py runserver --insecure
|
||||
|
||||
Examples of using different ports and addresses
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
@ -53,10 +53,10 @@ Default: ``'/static/admin/'``
|
|||
|
||||
The URL prefix for admin media -- CSS, JavaScript and images used by the Django
|
||||
administrative interface. Make sure to use a trailing slash, and to have this be
|
||||
different from the :setting:``MEDIA_URL`` setting (since the same URL cannot be
|
||||
different from the :setting:`MEDIA_URL` setting (since the same URL cannot be
|
||||
mapped onto two different sets of files). For integration with :doc:`staticfiles
|
||||
</ref/contrib/staticfiles>`, this should be the same as
|
||||
:setting:`STATICFILES_URL` followed by ``'admin/'``.
|
||||
:setting:`STATIC_URL` followed by ``'admin/'``.
|
||||
|
||||
.. setting:: ADMINS
|
||||
|
||||
|
@ -1122,12 +1122,12 @@ Default: ``''`` (Empty string)
|
|||
URL that handles the media served from :setting:`MEDIA_ROOT`, used
|
||||
for :doc:`managing stored files </topics/files>`.
|
||||
|
||||
Example: ``"http://media.lawrence.com"``
|
||||
Example: ``"http://media.lawrence.com/"``
|
||||
|
||||
Note that this should have a trailing slash if it has a path component.
|
||||
|
||||
* Good: ``"http://www.example.com/static/"``
|
||||
* Bad: ``"http://www.example.com/static"``
|
||||
* Good: ``"http://www.example.com/media/"``
|
||||
* Bad: ``"http://www.example.com/media"``
|
||||
|
||||
MESSAGE_LEVEL
|
||||
-------------
|
||||
|
@ -1486,6 +1486,49 @@ See :doc:`/ref/contrib/sites`.
|
|||
|
||||
.. _site framework docs: ../sites/
|
||||
|
||||
.. setting:: STATIC_ROOT
|
||||
|
||||
STATIC_ROOT
|
||||
-----------
|
||||
|
||||
Default: ``''`` (Empty string)
|
||||
|
||||
The absolute path to the directory that contains static content.
|
||||
|
||||
Example: ``"/home/example.com/static/"``
|
||||
|
||||
When using the :djadmin:`collectstatic` management command of the optional,
|
||||
:doc:`staticfiles</ref/contrib/staticfiles>` app this will be used to collect
|
||||
static files into and served from :setting:`STATIC_URL`.
|
||||
|
||||
In that case this is a **required setting**, unless you've overridden
|
||||
:setting:`STATICFILES_STORAGE` and are using a custom storage backend.
|
||||
|
||||
This is not a place to store your static files permanently under version
|
||||
control; you should do that in directories that will be found by your
|
||||
:setting:`STATICFILES_FINDERS` (by default, per-app ``static/`` subdirectories,
|
||||
and any directories you include in :setting:`STATICFILES_DIRS`). Files from
|
||||
those locations will be collected into :setting:`STATIC_ROOT`.
|
||||
|
||||
See :doc:`/ref/contrib/staticfiles` and :setting:`STATIC_URL`.
|
||||
|
||||
.. setting:: STATIC_URL
|
||||
|
||||
STATIC_URL
|
||||
----------
|
||||
|
||||
Default: ``None``
|
||||
|
||||
URL that handles the files served from :setting:`STATIC_ROOT`.
|
||||
|
||||
Example: ``"/site_media/static/"`` or ``"http://static.example.com/"``
|
||||
|
||||
If not ``None``, this will be used as the base path for
|
||||
:ref:`media definitions<form-media-paths>` and the
|
||||
:doc:`staticfiles app</ref/contrib/staticfiles>`.
|
||||
|
||||
See :setting:`STATIC_ROOT`.
|
||||
|
||||
.. setting:: TEMPLATE_CONTEXT_PROCESSORS
|
||||
|
||||
TEMPLATE_CONTEXT_PROCESSORS
|
||||
|
@ -1496,7 +1539,8 @@ Default::
|
|||
("django.contrib.auth.context_processors.auth",
|
||||
"django.core.context_processors.debug",
|
||||
"django.core.context_processors.i18n",
|
||||
"django.contrib.staticfiles.context_processors.staticfiles",
|
||||
"django.core.context_processors.media",
|
||||
"django.core.context_processors.static",
|
||||
"django.contrib.messages.context_processors.messages")
|
||||
|
||||
A tuple of callables that are used to populate the context in ``RequestContext``.
|
||||
|
@ -1513,6 +1557,10 @@ of items to be merged into the context.
|
|||
``django.core.context_processors.auth`` to
|
||||
``django.contrib.auth.context_processors.auth``.
|
||||
|
||||
.. versionadded:: 1.3
|
||||
The ``django.core.context_processors.static`` context processor
|
||||
was added in this release.
|
||||
|
||||
.. setting:: TEMPLATE_DEBUG
|
||||
|
||||
TEMPLATE_DEBUG
|
||||
|
|
|
@ -312,8 +312,8 @@ and return a dictionary of items to be merged into the context. By default,
|
|||
"django.core.context_processors.debug",
|
||||
"django.core.context_processors.i18n",
|
||||
"django.core.context_processors.media",
|
||||
"django.contrib.messages.context_processors.messages",
|
||||
"django.contrib.staticfiles.context_processors.staticfiles")
|
||||
"django.core.context_processors.static",
|
||||
"django.contrib.messages.context_processors.messages")
|
||||
|
||||
.. versionadded:: 1.2
|
||||
In addition to these, ``RequestContext`` always uses
|
||||
|
@ -435,6 +435,15 @@ If :setting:`TEMPLATE_CONTEXT_PROCESSORS` contains this processor, every
|
|||
``RequestContext`` will contain a variable ``MEDIA_URL``, providing the
|
||||
value of the :setting:`MEDIA_URL` setting.
|
||||
|
||||
django.core.context_processors.static
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. versionadded:: 1.3
|
||||
|
||||
If :setting:`TEMPLATE_CONTEXT_PROCESSORS` contains this processor, every
|
||||
``RequestContext`` will contain a variable ``STATIC_URL``, providing the
|
||||
value of the :setting:`STATIC_URL` setting.
|
||||
|
||||
django.core.context_processors.csrf
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ changes`_ and an easy upgrade path from Django 1.2.
|
|||
|
||||
.. _new features: `What's new in Django 1.3 alpha 1`_
|
||||
|
||||
.. _backwards incompatible changes: backwards-incompatible-changes-1.3_
|
||||
.. _backwards incompatible changes: backwards-incompatible-changes-1.3-alpha-1_
|
||||
|
||||
What's new in Django 1.3 alpha 1
|
||||
================================
|
||||
|
@ -161,7 +161,7 @@ requests. These include:
|
|||
easier to test the database activity associated with a view.
|
||||
|
||||
|
||||
.. _backwards-incompatible-changes-1.3:
|
||||
.. _backwards-incompatible-changes-1.3-alpha-1:
|
||||
|
||||
Backwards-incompatible changes in 1.3 alpha 1
|
||||
=============================================
|
||||
|
@ -270,8 +270,6 @@ local flavors:
|
|||
official designation "Aceh (ACE)".
|
||||
|
||||
|
||||
.. _deprecated-features-1.3:
|
||||
|
||||
Features deprecated in 1.3
|
||||
==========================
|
||||
|
||||
|
|
|
@ -13,10 +13,6 @@ prior to the final 1.3 release.
|
|||
As such, this release is *not* intended for production use, and any such use
|
||||
is discouraged.
|
||||
|
||||
.. _new features: `What's new in Django 1.3 alpha 2`_
|
||||
|
||||
.. _backwards incompatible changes: backwards-incompatible-changes-1.3-alpha-2_
|
||||
|
||||
What's new in Django 1.3 alpha 2
|
||||
================================
|
||||
|
||||
|
@ -43,6 +39,47 @@ See the :doc:`reference documentation of the app </ref/contrib/staticfiles>`
|
|||
for more details or learn how to :doc:`manage static files
|
||||
</howto/static-files>`.
|
||||
|
||||
Backwards-incompatible changes in 1.3 alpha 2
|
||||
=============================================
|
||||
|
||||
Introduction of STATIC_URL and STATIC_ROOT settings
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The newly introduced :doc:`/ref/contrib/staticfiles` app extends Django's
|
||||
abilities to handle static app and project files, required the additon of
|
||||
settings to refer to those files in templates and code, especially in
|
||||
contrast to the :setting:`MEDIA_URL` and :setting:`MEDIA_ROOT` settings that
|
||||
refer to user-uploaded files.
|
||||
|
||||
Prior to 1.3 alpha 2 these settings were called ``STATICFILES_URL`` and
|
||||
``STATICFILES_ROOT`` to follow the naming scheme for app centric settings.
|
||||
Based on feedback from the community it became apparent that those settings
|
||||
created confusion, especially given the fact handling static files is also
|
||||
desired outside the use of the optional ``staticfiles`` app.
|
||||
|
||||
As a result, we take the followig steps to rectify the issue:
|
||||
|
||||
* Two new global settings that will be used by -- **but are not limited
|
||||
to** -- the :doc:`staticfiles</ref/contrib/staticfiles>` app:
|
||||
|
||||
* :setting:`STATIC_ROOT` (formally ``STATICFILES_ROOT``)
|
||||
|
||||
* :setting:`STATIC_URL` (formally ``STATICFILES_URL``)
|
||||
|
||||
* Moving the
|
||||
``django.contrib.staticfiles.templatetags.staticfiles.get_staticfiles_prefix``
|
||||
template tag to the core (``django.templatetags.static``) and renaming
|
||||
it to :ttag:`get_static_prefix`.
|
||||
|
||||
* Moving the context processor
|
||||
``django.contrib.staticfiles.context_processors.staticfiles`` to the
|
||||
core (``django.core.context_processors.static``) and renaming it to
|
||||
:func:`~django.core.context_processors.static`.
|
||||
|
||||
* :ref:`form-media-paths` will use :setting:`STATIC_URL` as the prefix
|
||||
**if the value is not None**, and falls back to the previously used
|
||||
:setting:`MEDIA_URL`.
|
||||
|
||||
The Django 1.3 roadmap
|
||||
======================
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ In previous versions of Django, it was common to place static assets in
|
|||
app is to make it easier to keep static files separate from user-uploaded
|
||||
files. For this reason, you will probably want to make your
|
||||
:setting:`MEDIA_ROOT` and :setting:`MEDIA_URL` different from your
|
||||
:setting:`STATICFILES_ROOT` and :setting:`STATICFILES_URL`. You will need to
|
||||
:setting:`STATIC_ROOT` and :setting:`STATIC_URL`. You will need to
|
||||
arrange for serving of files in :setting:`MEDIA_ROOT` yourself;
|
||||
``staticfiles`` does not deal with user-uploaded media at all.
|
||||
|
||||
|
|
|
@ -64,6 +64,7 @@ notes.
|
|||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
1.3-alpha-2
|
||||
1.3-alpha-1
|
||||
1.2-rc-1
|
||||
1.2-beta-1
|
||||
|
|
|
@ -190,16 +190,30 @@ also be defined in a dynamic fashion::
|
|||
See the section on `Media objects`_ for more details on how to construct
|
||||
return values for dynamic media properties.
|
||||
|
||||
.. _form-media-paths:
|
||||
|
||||
Paths in media definitions
|
||||
--------------------------
|
||||
|
||||
.. versionchanged:: 1.3
|
||||
|
||||
Paths used to specify media 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
|
||||
``settings.MEDIA_URL``. For example, if the MEDIA_URL for your site was
|
||||
``http://media.example.com/``::
|
||||
the appropriate prefix.
|
||||
|
||||
class CalendarWidget(forms.TextInput):
|
||||
As part of the introduction of the
|
||||
:doc:`staticfiles app </ref/contrib/staticfiles>` two new settings were added
|
||||
to refer to "static content" (images, CSS, Javascript, etc.) that are needed
|
||||
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
|
||||
:setting:`STATIC_URL` setting is not ``None`` and automatically fall back
|
||||
to using :setting:`MEDIA_URL`. For example, if the :setting:`MEDIA_URL` for
|
||||
your site was ``'http://uploads.example.com/'`` and :setting:`STATIC_URL`
|
||||
was ``None``::
|
||||
|
||||
>>> class CalendarWidget(forms.TextInput):
|
||||
class Media:
|
||||
css = {
|
||||
'all': ('/css/pretty.css',),
|
||||
|
@ -209,9 +223,18 @@ path, and left as-is. All other paths will be prepended with the value of
|
|||
>>> w = CalendarWidget()
|
||||
>>> print w.media
|
||||
<link href="/css/pretty.css" type="text/css" media="all" rel="stylesheet" />
|
||||
<script type="text/javascript" src="http://media.example.com/animations.js"></script>
|
||||
<script type="text/javascript" src="http://uploads.example.com/animations.js"></script>
|
||||
<script type="text/javascript" src="http://othersite.com/actions.js"></script>
|
||||
|
||||
But if :setting:`STATIC_URL` is ``'http://static.example.com/'``::
|
||||
|
||||
>>> w = CalendarWidget()
|
||||
>>> print w.media
|
||||
<link href="/css/pretty.css" type="text/css" media="all" rel="stylesheet" />
|
||||
<script type="text/javascript" src="http://static.example.com/animations.js"></script>
|
||||
<script type="text/javascript" src="http://othersite.com/actions.js"></script>
|
||||
|
||||
|
||||
Media objects
|
||||
-------------
|
||||
|
||||
|
|
|
@ -458,3 +458,463 @@ class FormsMediaTestCase(TestCase):
|
|||
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
|
||||
<link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
|
||||
<link href="/some/form/css" type="text/css" media="all" rel="stylesheet" />""")
|
||||
|
||||
|
||||
class StaticFormsMediaTestCase(TestCase):
|
||||
# Tests for the media handling on widgets and forms
|
||||
def setUp(self):
|
||||
super(StaticFormsMediaTestCase, self).setUp()
|
||||
self.original_media_url = settings.MEDIA_URL
|
||||
self.original_static_url = settings.STATIC_URL
|
||||
settings.MEDIA_URL = 'http://media.example.com/static/'
|
||||
settings.STATIC_URL = 'http://media.example.com/static/'
|
||||
|
||||
def tearDown(self):
|
||||
settings.MEDIA_URL = self.original_media_url
|
||||
settings.STATIC_URL = self.original_static_url
|
||||
super(StaticFormsMediaTestCase, self).tearDown()
|
||||
|
||||
def test_construction(self):
|
||||
# Check construction of media objects
|
||||
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="http://media.example.com/static/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>""")
|
||||
|
||||
class Foo:
|
||||
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')
|
||||
|
||||
m3 = Media(Foo)
|
||||
self.assertEqual(str(m3), """<link href="http://media.example.com/static/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>""")
|
||||
|
||||
# A widget can exist without a media definition
|
||||
class MyWidget(TextInput):
|
||||
pass
|
||||
|
||||
w = MyWidget()
|
||||
self.assertEqual(str(w.media), '')
|
||||
|
||||
def test_media_dsl(self):
|
||||
###############################################################
|
||||
# DSL Class-based media definitions
|
||||
###############################################################
|
||||
|
||||
# A widget can define media if it needs to.
|
||||
# Any absolute path will be preserved; relative paths are combined
|
||||
# with the value of settings.MEDIA_URL
|
||||
class MyWidget1(TextInput):
|
||||
class 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')
|
||||
|
||||
w1 = MyWidget1()
|
||||
self.assertEqual(str(w1.media), """<link href="http://media.example.com/static/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>""")
|
||||
|
||||
# Media objects can be interrogated by media type
|
||||
self.assertEqual(str(w1.media['css']), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
|
||||
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />""")
|
||||
|
||||
self.assertEqual(str(w1.media['js']), """<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>""")
|
||||
|
||||
def test_combine_media(self):
|
||||
# Media objects can be combined. Any given media resource will appear only
|
||||
# once. Duplicated media definitions are ignored.
|
||||
class MyWidget1(TextInput):
|
||||
class 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')
|
||||
|
||||
class MyWidget2(TextInput):
|
||||
class Media:
|
||||
css = {
|
||||
'all': ('/path/to/css2','/path/to/css3')
|
||||
}
|
||||
js = ('/path/to/js1','/path/to/js4')
|
||||
|
||||
class MyWidget3(TextInput):
|
||||
class Media:
|
||||
css = {
|
||||
'all': ('/path/to/css3','path/to/css1')
|
||||
}
|
||||
js = ('/path/to/js1','/path/to/js4')
|
||||
|
||||
w1 = MyWidget1()
|
||||
w2 = MyWidget2()
|
||||
w3 = MyWidget3()
|
||||
self.assertEqual(str(w1.media + w2.media + w3.media), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
|
||||
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
|
||||
<link href="/path/to/css3" 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>
|
||||
<script type="text/javascript" src="/path/to/js4"></script>""")
|
||||
|
||||
# Check that media addition hasn't affected the original objects
|
||||
self.assertEqual(str(w1.media), """<link href="http://media.example.com/static/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>""")
|
||||
|
||||
# Regression check for #12879: specifying the same CSS or JS file
|
||||
# multiple times in a single Media instance should result in that file
|
||||
# only being included once.
|
||||
class MyWidget4(TextInput):
|
||||
class Media:
|
||||
css = {'all': ('/path/to/css1', '/path/to/css1')}
|
||||
js = ('/path/to/js1', '/path/to/js1')
|
||||
|
||||
w4 = MyWidget4()
|
||||
self.assertEqual(str(w4.media), """<link href="/path/to/css1" type="text/css" media="all" rel="stylesheet" />
|
||||
<script type="text/javascript" src="/path/to/js1"></script>""")
|
||||
|
||||
def test_media_property(self):
|
||||
###############################################################
|
||||
# Property-based media definitions
|
||||
###############################################################
|
||||
|
||||
# Widget media can be defined as a property
|
||||
class MyWidget4(TextInput):
|
||||
def _media(self):
|
||||
return Media(css={'all': ('/some/path',)}, js = ('/some/js',))
|
||||
media = property(_media)
|
||||
|
||||
w4 = MyWidget4()
|
||||
self.assertEqual(str(w4.media), """<link href="/some/path" type="text/css" media="all" rel="stylesheet" />
|
||||
<script type="text/javascript" src="/some/js"></script>""")
|
||||
|
||||
# Media properties can reference the media of their parents
|
||||
class MyWidget5(MyWidget4):
|
||||
def _media(self):
|
||||
return super(MyWidget5, self).media + Media(css={'all': ('/other/path',)}, js = ('/other/js',))
|
||||
media = property(_media)
|
||||
|
||||
w5 = MyWidget5()
|
||||
self.assertEqual(str(w5.media), """<link href="/some/path" type="text/css" media="all" rel="stylesheet" />
|
||||
<link href="/other/path" type="text/css" media="all" rel="stylesheet" />
|
||||
<script type="text/javascript" src="/some/js"></script>
|
||||
<script type="text/javascript" src="/other/js"></script>""")
|
||||
|
||||
def test_media_property_parent_references(self):
|
||||
# Media properties can reference the media of their parents,
|
||||
# even if the parent media was defined using a class
|
||||
class MyWidget1(TextInput):
|
||||
class 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')
|
||||
|
||||
class MyWidget6(MyWidget1):
|
||||
def _media(self):
|
||||
return super(MyWidget6, self).media + Media(css={'all': ('/other/path',)}, js = ('/other/js',))
|
||||
media = property(_media)
|
||||
|
||||
w6 = MyWidget6()
|
||||
self.assertEqual(str(w6.media), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
|
||||
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
|
||||
<link href="/other/path" 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>
|
||||
<script type="text/javascript" src="/other/js"></script>""")
|
||||
|
||||
def test_media_inheritance(self):
|
||||
###############################################################
|
||||
# Inheritance of media
|
||||
###############################################################
|
||||
|
||||
# If a widget extends another but provides no media definition, it inherits the parent widget's media
|
||||
class MyWidget1(TextInput):
|
||||
class 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')
|
||||
|
||||
class MyWidget7(MyWidget1):
|
||||
pass
|
||||
|
||||
w7 = MyWidget7()
|
||||
self.assertEqual(str(w7.media), """<link href="http://media.example.com/static/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>""")
|
||||
|
||||
# If a widget extends another but defines media, it extends the parent widget's media by default
|
||||
class MyWidget8(MyWidget1):
|
||||
class Media:
|
||||
css = {
|
||||
'all': ('/path/to/css3','path/to/css1')
|
||||
}
|
||||
js = ('/path/to/js1','/path/to/js4')
|
||||
|
||||
w8 = MyWidget8()
|
||||
self.assertEqual(str(w8.media), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
|
||||
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
|
||||
<link href="/path/to/css3" 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>
|
||||
<script type="text/javascript" src="/path/to/js4"></script>""")
|
||||
|
||||
def test_media_inheritance_from_property(self):
|
||||
# If a widget extends another but defines media, it extends the parents widget's media,
|
||||
# even if the parent defined media using a property.
|
||||
class MyWidget1(TextInput):
|
||||
class 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')
|
||||
|
||||
class MyWidget4(TextInput):
|
||||
def _media(self):
|
||||
return Media(css={'all': ('/some/path',)}, js = ('/some/js',))
|
||||
media = property(_media)
|
||||
|
||||
class MyWidget9(MyWidget4):
|
||||
class Media:
|
||||
css = {
|
||||
'all': ('/other/path',)
|
||||
}
|
||||
js = ('/other/js',)
|
||||
|
||||
w9 = MyWidget9()
|
||||
self.assertEqual(str(w9.media), """<link href="/some/path" type="text/css" media="all" rel="stylesheet" />
|
||||
<link href="/other/path" type="text/css" media="all" rel="stylesheet" />
|
||||
<script type="text/javascript" src="/some/js"></script>
|
||||
<script type="text/javascript" src="/other/js"></script>""")
|
||||
|
||||
# A widget can disable media inheritance by specifying 'extend=False'
|
||||
class MyWidget10(MyWidget1):
|
||||
class Media:
|
||||
extend = False
|
||||
css = {
|
||||
'all': ('/path/to/css3','path/to/css1')
|
||||
}
|
||||
js = ('/path/to/js1','/path/to/js4')
|
||||
|
||||
w10 = MyWidget10()
|
||||
self.assertEqual(str(w10.media), """<link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
|
||||
<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
|
||||
<script type="text/javascript" src="/path/to/js1"></script>
|
||||
<script type="text/javascript" src="/path/to/js4"></script>""")
|
||||
|
||||
def test_media_inheritance_extends(self):
|
||||
# A widget can explicitly enable full media inheritance by specifying 'extend=True'
|
||||
class MyWidget1(TextInput):
|
||||
class 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')
|
||||
|
||||
class MyWidget11(MyWidget1):
|
||||
class Media:
|
||||
extend = True
|
||||
css = {
|
||||
'all': ('/path/to/css3','path/to/css1')
|
||||
}
|
||||
js = ('/path/to/js1','/path/to/js4')
|
||||
|
||||
w11 = MyWidget11()
|
||||
self.assertEqual(str(w11.media), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
|
||||
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
|
||||
<link href="/path/to/css3" 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>
|
||||
<script type="text/javascript" src="/path/to/js4"></script>""")
|
||||
|
||||
def test_media_inheritance_single_type(self):
|
||||
# A widget can enable inheritance of one media type by specifying extend as a tuple
|
||||
class MyWidget1(TextInput):
|
||||
class 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')
|
||||
|
||||
class MyWidget12(MyWidget1):
|
||||
class Media:
|
||||
extend = ('css',)
|
||||
css = {
|
||||
'all': ('/path/to/css3','path/to/css1')
|
||||
}
|
||||
js = ('/path/to/js1','/path/to/js4')
|
||||
|
||||
w12 = MyWidget12()
|
||||
self.assertEqual(str(w12.media), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
|
||||
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
|
||||
<link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
|
||||
<script type="text/javascript" src="/path/to/js1"></script>
|
||||
<script type="text/javascript" src="/path/to/js4"></script>""")
|
||||
|
||||
def test_multi_media(self):
|
||||
###############################################################
|
||||
# Multi-media handling for CSS
|
||||
###############################################################
|
||||
|
||||
# A widget can define CSS media for multiple output media types
|
||||
class MultimediaWidget(TextInput):
|
||||
class Media:
|
||||
css = {
|
||||
'screen, print': ('/file1','/file2'),
|
||||
'screen': ('/file3',),
|
||||
'print': ('/file4',)
|
||||
}
|
||||
js = ('/path/to/js1','/path/to/js4')
|
||||
|
||||
multimedia = MultimediaWidget()
|
||||
self.assertEqual(str(multimedia.media), """<link href="/file4" type="text/css" media="print" rel="stylesheet" />
|
||||
<link href="/file3" type="text/css" media="screen" rel="stylesheet" />
|
||||
<link href="/file1" type="text/css" media="screen, print" rel="stylesheet" />
|
||||
<link href="/file2" type="text/css" media="screen, print" rel="stylesheet" />
|
||||
<script type="text/javascript" src="/path/to/js1"></script>
|
||||
<script type="text/javascript" src="/path/to/js4"></script>""")
|
||||
|
||||
def test_multi_widget(self):
|
||||
###############################################################
|
||||
# Multiwidget media handling
|
||||
###############################################################
|
||||
|
||||
class MyWidget1(TextInput):
|
||||
class 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')
|
||||
|
||||
class MyWidget2(TextInput):
|
||||
class Media:
|
||||
css = {
|
||||
'all': ('/path/to/css2','/path/to/css3')
|
||||
}
|
||||
js = ('/path/to/js1','/path/to/js4')
|
||||
|
||||
class MyWidget3(TextInput):
|
||||
class Media:
|
||||
css = {
|
||||
'all': ('/path/to/css3','path/to/css1')
|
||||
}
|
||||
js = ('/path/to/js1','/path/to/js4')
|
||||
|
||||
# MultiWidgets have a default media definition that gets all the
|
||||
# media from the component widgets
|
||||
class MyMultiWidget(MultiWidget):
|
||||
def __init__(self, attrs=None):
|
||||
widgets = [MyWidget1, MyWidget2, MyWidget3]
|
||||
super(MyMultiWidget, self).__init__(widgets, attrs)
|
||||
|
||||
mymulti = MyMultiWidget()
|
||||
self.assertEqual(str(mymulti.media), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
|
||||
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
|
||||
<link href="/path/to/css3" 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>
|
||||
<script type="text/javascript" src="/path/to/js4"></script>""")
|
||||
|
||||
def test_form_media(self):
|
||||
###############################################################
|
||||
# Media processing for forms
|
||||
###############################################################
|
||||
|
||||
class MyWidget1(TextInput):
|
||||
class 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')
|
||||
|
||||
class MyWidget2(TextInput):
|
||||
class Media:
|
||||
css = {
|
||||
'all': ('/path/to/css2','/path/to/css3')
|
||||
}
|
||||
js = ('/path/to/js1','/path/to/js4')
|
||||
|
||||
class MyWidget3(TextInput):
|
||||
class Media:
|
||||
css = {
|
||||
'all': ('/path/to/css3','path/to/css1')
|
||||
}
|
||||
js = ('/path/to/js1','/path/to/js4')
|
||||
|
||||
# You can ask a form for the media required by its widgets.
|
||||
class MyForm(Form):
|
||||
field1 = CharField(max_length=20, widget=MyWidget1())
|
||||
field2 = CharField(max_length=20, widget=MyWidget2())
|
||||
f1 = MyForm()
|
||||
self.assertEqual(str(f1.media), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
|
||||
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
|
||||
<link href="/path/to/css3" 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>
|
||||
<script type="text/javascript" src="/path/to/js4"></script>""")
|
||||
|
||||
# Form media can be combined to produce a single media definition.
|
||||
class AnotherForm(Form):
|
||||
field3 = CharField(max_length=20, widget=MyWidget3())
|
||||
f2 = AnotherForm()
|
||||
self.assertEqual(str(f1.media + f2.media), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
|
||||
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
|
||||
<link href="/path/to/css3" 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>
|
||||
<script type="text/javascript" src="/path/to/js4"></script>""")
|
||||
|
||||
# Forms can also define media, following the same rules as widgets.
|
||||
class FormWithMedia(Form):
|
||||
field1 = CharField(max_length=20, widget=MyWidget1())
|
||||
field2 = CharField(max_length=20, widget=MyWidget2())
|
||||
class Media:
|
||||
js = ('/some/form/javascript',)
|
||||
css = {
|
||||
'all': ('/some/form/css',)
|
||||
}
|
||||
f3 = FormWithMedia()
|
||||
self.assertEqual(str(f3.media), """<link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
|
||||
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
|
||||
<link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
|
||||
<link href="/some/form/css" 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>
|
||||
<script type="text/javascript" src="/path/to/js4"></script>
|
||||
<script type="text/javascript" src="/some/form/javascript"></script>""")
|
||||
|
||||
# Media works in templates
|
||||
from django.template import Template, Context
|
||||
self.assertEqual(Template("{{ form.media.js }}{{ form.media.css }}").render(Context({'form': f3})), """<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>
|
||||
<script type="text/javascript" src="/path/to/js4"></script>
|
||||
<script type="text/javascript" src="/some/form/javascript"></script><link href="http://media.example.com/static/path/to/css1" type="text/css" media="all" rel="stylesheet" />
|
||||
<link href="/path/to/css2" type="text/css" media="all" rel="stylesheet" />
|
||||
<link href="/path/to/css3" type="text/css" media="all" rel="stylesheet" />
|
||||
<link href="/some/form/css" type="text/css" media="all" rel="stylesheet" />""")
|
||||
|
||||
|
|
|
@ -23,8 +23,8 @@ class StaticFilesTestCase(TestCase):
|
|||
Test case with a couple utility assertions.
|
||||
"""
|
||||
def setUp(self):
|
||||
self.old_staticfiles_url = settings.STATICFILES_URL
|
||||
self.old_staticfiles_root = settings.STATICFILES_ROOT
|
||||
self.old_static_url = settings.STATIC_URL
|
||||
self.old_static_root = settings.STATIC_ROOT
|
||||
self.old_staticfiles_dirs = settings.STATICFILES_DIRS
|
||||
self.old_staticfiles_finders = settings.STATICFILES_FINDERS
|
||||
self.old_media_root = settings.MEDIA_ROOT
|
||||
|
@ -40,8 +40,8 @@ class StaticFilesTestCase(TestCase):
|
|||
settings.DEBUG = True
|
||||
settings.MEDIA_ROOT = os.path.join(site_media, 'media')
|
||||
settings.MEDIA_URL = '/media/'
|
||||
settings.STATICFILES_ROOT = os.path.join(site_media, 'static')
|
||||
settings.STATICFILES_URL = '/static/'
|
||||
settings.STATIC_ROOT = os.path.join(site_media, 'static')
|
||||
settings.STATIC_URL = '/static/'
|
||||
settings.ADMIN_MEDIA_PREFIX = '/static/admin/'
|
||||
settings.STATICFILES_DIRS = (
|
||||
os.path.join(TEST_ROOT, 'project', 'documents'),
|
||||
|
@ -52,6 +52,7 @@ class StaticFilesTestCase(TestCase):
|
|||
'django.contrib.staticfiles.finders.DefaultStorageFinder',
|
||||
)
|
||||
settings.INSTALLED_APPS = [
|
||||
"django.contrib.staticfiles",
|
||||
"regressiontests.staticfiles_tests",
|
||||
]
|
||||
|
||||
|
@ -65,8 +66,8 @@ class StaticFilesTestCase(TestCase):
|
|||
settings.MEDIA_ROOT = self.old_media_root
|
||||
settings.MEDIA_URL = self.old_media_url
|
||||
settings.ADMIN_MEDIA_PREFIX = self.old_admin_media_prefix
|
||||
settings.STATICFILES_ROOT = self.old_staticfiles_root
|
||||
settings.STATICFILES_URL = self.old_staticfiles_url
|
||||
settings.STATIC_ROOT = self.old_static_root
|
||||
settings.STATIC_URL = self.old_static_url
|
||||
settings.STATICFILES_DIRS = self.old_staticfiles_dirs
|
||||
settings.STATICFILES_FINDERS = self.old_staticfiles_finders
|
||||
settings.INSTALLED_APPS = self.old_installed_apps
|
||||
|
@ -91,13 +92,13 @@ class BuildStaticTestCase(StaticFilesTestCase):
|
|||
def setUp(self):
|
||||
super(BuildStaticTestCase, self).setUp()
|
||||
self.old_staticfiles_storage = settings.STATICFILES_STORAGE
|
||||
self.old_root = settings.STATICFILES_ROOT
|
||||
settings.STATICFILES_ROOT = tempfile.mkdtemp()
|
||||
self.old_root = settings.STATIC_ROOT
|
||||
settings.STATIC_ROOT = tempfile.mkdtemp()
|
||||
self.run_collectstatic()
|
||||
|
||||
def tearDown(self):
|
||||
shutil.rmtree(settings.STATICFILES_ROOT)
|
||||
settings.STATICFILES_ROOT = self.old_root
|
||||
shutil.rmtree(settings.STATIC_ROOT)
|
||||
settings.STATIC_ROOT = self.old_root
|
||||
super(BuildStaticTestCase, self).tearDown()
|
||||
|
||||
def run_collectstatic(self, **kwargs):
|
||||
|
@ -106,7 +107,7 @@ class BuildStaticTestCase(StaticFilesTestCase):
|
|||
|
||||
def _get_file(self, filepath):
|
||||
assert filepath, 'filepath is empty.'
|
||||
filepath = os.path.join(settings.STATICFILES_ROOT, filepath)
|
||||
filepath = os.path.join(settings.STATIC_ROOT, filepath)
|
||||
f = open(filepath)
|
||||
try:
|
||||
return f.read()
|
||||
|
@ -231,7 +232,7 @@ class TestBuildStaticDryRun(BuildStaticTestCase):
|
|||
"""
|
||||
With --dry-run, no files created in destination dir.
|
||||
"""
|
||||
self.assertEquals(os.listdir(settings.STATICFILES_ROOT), [])
|
||||
self.assertEquals(os.listdir(settings.STATIC_ROOT), [])
|
||||
|
||||
|
||||
if sys.platform != 'win32':
|
||||
|
@ -251,7 +252,7 @@ if sys.platform != 'win32':
|
|||
With ``--link``, symbolic links are created.
|
||||
|
||||
"""
|
||||
self.failUnless(os.path.islink(os.path.join(settings.STATICFILES_ROOT, 'test.txt')))
|
||||
self.failUnless(os.path.islink(os.path.join(settings.STATIC_ROOT, 'test.txt')))
|
||||
|
||||
|
||||
class TestServeStatic(StaticFilesTestCase):
|
||||
|
@ -262,7 +263,7 @@ class TestServeStatic(StaticFilesTestCase):
|
|||
|
||||
def _response(self, filepath):
|
||||
return self.client.get(
|
||||
posixpath.join(settings.STATICFILES_URL, filepath))
|
||||
posixpath.join(settings.STATIC_URL, filepath))
|
||||
|
||||
def assertFileContains(self, filepath, text):
|
||||
self.assertContains(self._response(filepath), text)
|
||||
|
@ -372,24 +373,3 @@ class TestMiscFinder(TestCase):
|
|||
finders.get_finder, "django.contrib.staticfiles.finders.FooBarFinder")
|
||||
self.assertRaises(ImproperlyConfigured,
|
||||
finders.get_finder, "foo.bar.FooBarFinder")
|
||||
|
||||
|
||||
class TemplateTagTest(TestCase):
|
||||
def test_get_staticfiles_prefix(self):
|
||||
"""
|
||||
Test the get_staticfiles_prefix helper return the STATICFILES_URL setting.
|
||||
"""
|
||||
self.assertEquals(Template(
|
||||
"{% load staticfiles %}"
|
||||
"{% get_staticfiles_prefix %}"
|
||||
).render(Context()), settings.STATICFILES_URL)
|
||||
|
||||
def test_get_staticfiles_prefix_with_as(self):
|
||||
"""
|
||||
Test the get_staticfiles_prefix helper return the STATICFILES_URL setting.
|
||||
"""
|
||||
self.assertEquals(Template(
|
||||
"{% load staticfiles %}"
|
||||
"{% get_staticfiles_prefix as staticfiles_prefix %}"
|
||||
"{{ staticfiles_prefix }}"
|
||||
).render(Context()), settings.STATICFILES_URL)
|
||||
|
|
|
@ -114,6 +114,16 @@ class UTF8Class:
|
|||
return u'ŠĐĆŽćžšđ'.encode('utf-8')
|
||||
|
||||
class Templates(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.old_static_url = settings.STATIC_URL
|
||||
self.old_media_url = settings.MEDIA_URL
|
||||
settings.STATIC_URL = u"/static/"
|
||||
settings.MEDIA_URL = u"/media/"
|
||||
|
||||
def tearDown(self):
|
||||
settings.STATIC_URL = self.old_static_url
|
||||
settings.MEDIA_URL = self.old_media_url
|
||||
|
||||
def test_loaders_security(self):
|
||||
ad_loader = app_directories.Loader()
|
||||
fs_loader = filesystem.Loader()
|
||||
|
@ -1328,24 +1338,28 @@ class Templates(unittest.TestCase):
|
|||
'autoescape-filtertag01': ("{{ first }}{% filter safe %}{{ first }} x<y{% endfilter %}", {"first": "<a>"}, template.TemplateSyntaxError),
|
||||
|
||||
# ifqeual compares unescaped vales.
|
||||
'autoescape-ifequal01': ('{% ifequal var "this & that" %}yes{% endifequal %}', { "var": "this & that" }, "yes" ),
|
||||
'autoescape-ifequal01': ('{% ifequal var "this & that" %}yes{% endifequal %}', { "var": "this & that" }, "yes"),
|
||||
|
||||
# Arguments to filters are 'safe' and manipulate their input unescaped.
|
||||
'autoescape-filters01': ('{{ var|cut:"&" }}', { "var": "this & that" }, "this that" ),
|
||||
'autoescape-filters02': ('{{ var|join:" & \" }}', { "var": ("Tom", "Dick", "Harry") }, "Tom & Dick & Harry" ),
|
||||
'autoescape-filters02': ('{{ var|join:" & \" }}', { "var": ("Tom", "Dick", "Harry") }, "Tom & Dick & Harry"),
|
||||
|
||||
# Literal strings are safe.
|
||||
'autoescape-literals01': ('{{ "this & that" }}',{}, "this & that" ),
|
||||
'autoescape-literals01': ('{{ "this & that" }}',{}, "this & that"),
|
||||
|
||||
# Iterating over strings outputs safe characters.
|
||||
'autoescape-stringiterations01': ('{% for l in var %}{{ l }},{% endfor %}', {'var': 'K&R'}, "K,&,R," ),
|
||||
'autoescape-stringiterations01': ('{% for l in var %}{{ l }},{% endfor %}', {'var': 'K&R'}, "K,&,R,"),
|
||||
|
||||
# Escape requirement survives lookup.
|
||||
'autoescape-lookup01': ('{{ var.key }}', { "var": {"key": "this & that" }}, "this & that" ),
|
||||
'autoescape-lookup01': ('{{ var.key }}', { "var": {"key": "this & that" }}, "this & that"),
|
||||
|
||||
# Static template tags
|
||||
'static-prefixtag01': ('{% load static %}{% get_static_prefix %}', {}, settings.STATIC_URL),
|
||||
'static-prefixtag02': ('{% load static %}{% get_static_prefix as static_prefix %}{{ static_prefix }}', {}, settings.STATIC_URL),
|
||||
'static-prefixtag03': ('{% load static %}{% get_media_prefix %}', {}, settings.MEDIA_URL),
|
||||
'static-prefixtag04': ('{% load static %}{% get_media_prefix as media_prefix %}{{ media_prefix }}', {}, settings.MEDIA_URL),
|
||||
}
|
||||
|
||||
|
||||
class TemplateTagLoading(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
|
Loading…
Reference in New Issue