mirror of
				https://github.com/django/django.git
				synced 2025-10-31 01:25:32 +00:00 
			
		
		
		
	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:
		| @@ -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" | ||||
|   | ||||
							
								
								
									
										84
									
								
								django/templatetags/static.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								django/templatetags/static.py
									
									
									
									
									
										Normal file
									
								
							| @@ -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): | ||||
|   | ||||
		Reference in New Issue
	
	Block a user