Deprecated TEMPLATE_LOADERS.

This commit is contained in:
Aymeric Augustin 2014-12-17 22:10:57 +01:00
parent d3a982556d
commit cf0fd65ed4
21 changed files with 315 additions and 226 deletions

View File

@ -0,0 +1,26 @@
import os
from django.utils._os import upath
AUTH_MIDDLEWARE_CLASSES = (
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
)
AUTH_TEMPLATES = [{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(os.path.dirname(upath(__file__)), 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': (
'django.contrib.auth.context_processors.auth',
'django.template.context_processors.debug',
'django.template.context_processors.i18n',
'django.template.context_processors.media',
'django.template.context_processors.static',
'django.template.context_processors.tz',
'django.contrib.messages.context_processors.messages',
),
},
}]

View File

@ -1,13 +1,12 @@
import os
from django.contrib.auth import authenticate from django.contrib.auth import authenticate
from django.contrib.auth.tests.utils import skipIfCustomUser
from django.contrib.auth.models import User, Permission from django.contrib.auth.models import User, Permission
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.contrib.auth.context_processors import PermWrapper, PermLookupDict from django.contrib.auth.context_processors import PermWrapper, PermLookupDict
from django.db.models import Q from django.db.models import Q
from django.test import TestCase, override_settings from django.test import TestCase, override_settings
from django.utils._os import upath
from .settings import AUTH_MIDDLEWARE_CLASSES, AUTH_TEMPLATES
from .utils import skipIfCustomUser
class MockUser(object): class MockUser(object):
@ -61,17 +60,10 @@ class PermWrapperTests(TestCase):
@skipIfCustomUser @skipIfCustomUser
@override_settings( @override_settings(
TEMPLATE_LOADERS=('django.template.loaders.filesystem.Loader',),
TEMPLATE_DIRS=(
os.path.join(os.path.dirname(upath(__file__)), 'templates'),
),
TEMPLATE_CONTEXT_PROCESSORS=(
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages'
),
ROOT_URLCONF='django.contrib.auth.tests.urls',
USE_TZ=False, # required for loading the fixture
PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',), PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',),
ROOT_URLCONF='django.contrib.auth.tests.urls',
TEMPLATES=AUTH_TEMPLATES,
USE_TZ=False, # required for loading the fixture
) )
class AuthContextProcessorTests(TestCase): class AuthContextProcessorTests(TestCase):
""" """
@ -79,12 +71,7 @@ class AuthContextProcessorTests(TestCase):
""" """
fixtures = ['context-processors-users.xml'] fixtures = ['context-processors-users.xml']
@override_settings( @override_settings(MIDDLEWARE_CLASSES=AUTH_MIDDLEWARE_CLASSES)
MIDDLEWARE_CLASSES=(
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
),
)
def test_session_not_accessed(self): def test_session_not_accessed(self):
""" """
Tests that the session is not accessed simply by including Tests that the session is not accessed simply by including
@ -93,12 +80,7 @@ class AuthContextProcessorTests(TestCase):
response = self.client.get('/auth_processor_no_attr_access/') response = self.client.get('/auth_processor_no_attr_access/')
self.assertContains(response, "Session not accessed") self.assertContains(response, "Session not accessed")
@override_settings( @override_settings(MIDDLEWARE_CLASSES=AUTH_MIDDLEWARE_CLASSES)
MIDDLEWARE_CLASSES=(
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
),
)
def test_session_is_accessed(self): def test_session_is_accessed(self):
""" """
Tests that the session is accessed if the auth context processor Tests that the session is accessed if the auth context processor

View File

@ -1,6 +1,5 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import os
import re import re
from django import forms from django import forms
@ -8,17 +7,18 @@ from django.contrib.auth.models import User
from django.contrib.auth.forms import (UserCreationForm, AuthenticationForm, from django.contrib.auth.forms import (UserCreationForm, AuthenticationForm,
PasswordChangeForm, SetPasswordForm, UserChangeForm, PasswordResetForm, PasswordChangeForm, SetPasswordForm, UserChangeForm, PasswordResetForm,
ReadOnlyPasswordHashField, ReadOnlyPasswordHashWidget) ReadOnlyPasswordHashField, ReadOnlyPasswordHashWidget)
from django.contrib.auth.tests.utils import skipIfCustomUser
from django.core import mail from django.core import mail
from django.core.mail import EmailMultiAlternatives from django.core.mail import EmailMultiAlternatives
from django.forms.fields import Field, CharField from django.forms.fields import Field, CharField
from django.test import TestCase, override_settings from django.test import TestCase, override_settings
from django.utils.encoding import force_text from django.utils.encoding import force_text
from django.utils._os import upath
from django.utils import translation from django.utils import translation
from django.utils.text import capfirst from django.utils.text import capfirst
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from .settings import AUTH_TEMPLATES
from .utils import skipIfCustomUser
@skipIfCustomUser @skipIfCustomUser
@override_settings(USE_TZ=False, PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',)) @override_settings(USE_TZ=False, PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',))
@ -360,10 +360,7 @@ class UserChangeFormTest(TestCase):
@skipIfCustomUser @skipIfCustomUser
@override_settings( @override_settings(
PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',), PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',),
TEMPLATE_LOADERS=('django.template.loaders.filesystem.Loader',), TEMPLATES=AUTH_TEMPLATES,
TEMPLATE_DIRS=(
os.path.join(os.path.dirname(upath(__file__)), 'templates'),
),
USE_TZ=False, USE_TZ=False,
) )
class PasswordResetFormTest(TestCase): class PasswordResetFormTest(TestCase):
@ -416,33 +413,31 @@ class PasswordResetFormTest(TestCase):
self.assertEqual(mail.outbox[0].subject, 'Custom password reset on example.com') self.assertEqual(mail.outbox[0].subject, 'Custom password reset on example.com')
def test_custom_email_constructor(self): def test_custom_email_constructor(self):
template_path = os.path.join(os.path.dirname(__file__), 'templates') data = {'email': 'testclient@example.com'}
with self.settings(TEMPLATE_DIRS=(template_path,)):
data = {'email': 'testclient@example.com'}
class CustomEmailPasswordResetForm(PasswordResetForm): class CustomEmailPasswordResetForm(PasswordResetForm):
def send_mail(self, subject_template_name, email_template_name, def send_mail(self, subject_template_name, email_template_name,
context, from_email, to_email, context, from_email, to_email,
html_email_template_name=None): html_email_template_name=None):
EmailMultiAlternatives( EmailMultiAlternatives(
"Forgot your password?", "Forgot your password?",
"Sorry to hear you forgot your password.", "Sorry to hear you forgot your password.",
None, [to_email], None, [to_email],
['site_monitor@example.com'], ['site_monitor@example.com'],
headers={'Reply-To': 'webmaster@example.com'}, headers={'Reply-To': 'webmaster@example.com'},
alternatives=[("Really sorry to hear you forgot your password.", alternatives=[("Really sorry to hear you forgot your password.",
"text/html")]).send() "text/html")]).send()
form = CustomEmailPasswordResetForm(data) form = CustomEmailPasswordResetForm(data)
self.assertTrue(form.is_valid()) self.assertTrue(form.is_valid())
# Since we're not providing a request object, we must provide a # Since we're not providing a request object, we must provide a
# domain_override to prevent the save operation from failing in the # domain_override to prevent the save operation from failing in the
# potential case where contrib.sites is not installed. Refs #16412. # potential case where contrib.sites is not installed. Refs #16412.
form.save(domain_override='example.com') form.save(domain_override='example.com')
self.assertEqual(len(mail.outbox), 1) self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].subject, 'Forgot your password?') self.assertEqual(mail.outbox[0].subject, 'Forgot your password?')
self.assertEqual(mail.outbox[0].bcc, ['site_monitor@example.com']) self.assertEqual(mail.outbox[0].bcc, ['site_monitor@example.com'])
self.assertEqual(mail.outbox[0].content_subtype, "plain") self.assertEqual(mail.outbox[0].content_subtype, "plain")
def test_preserve_username_case(self): def test_preserve_username_case(self):
""" """

View File

@ -1,14 +1,17 @@
from importlib import import_module from importlib import import_module
import itertools import itertools
import os
import re import re
import warnings import warnings
from django.apps import apps from django.apps import apps
from django.conf import global_settings, settings from django.conf import settings
from django.contrib.sites.requests import RequestSite from django.contrib.sites.requests import RequestSite
from django.contrib.admin.models import LogEntry from django.contrib.admin.models import LogEntry
from django.contrib.auth import SESSION_KEY, REDIRECT_FIELD_NAME
from django.contrib.auth.forms import (AuthenticationForm, PasswordChangeForm,
SetPasswordForm)
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib.auth.views import login as login_view
from django.core import mail from django.core import mail
from django.core.urlresolvers import reverse, NoReverseMatch from django.core.urlresolvers import reverse, NoReverseMatch
from django.http import QueryDict, HttpRequest from django.http import QueryDict, HttpRequest
@ -16,19 +19,15 @@ from django.utils.encoding import force_text
from django.utils.http import urlquote from django.utils.http import urlquote
from django.utils.six.moves.urllib.parse import urlparse, ParseResult from django.utils.six.moves.urllib.parse import urlparse, ParseResult
from django.utils.translation import LANGUAGE_SESSION_KEY from django.utils.translation import LANGUAGE_SESSION_KEY
from django.utils._os import upath
from django.test import TestCase, override_settings from django.test import TestCase, override_settings
from django.test.utils import patch_logger from django.test.utils import patch_logger
from django.middleware.csrf import CsrfViewMiddleware from django.middleware.csrf import CsrfViewMiddleware
from django.contrib.sessions.middleware import SessionMiddleware from django.contrib.sessions.middleware import SessionMiddleware
from django.contrib.auth import SESSION_KEY, REDIRECT_FIELD_NAME
from django.contrib.auth.forms import (AuthenticationForm, PasswordChangeForm,
SetPasswordForm)
# Needed so model is installed when tests are run independently: # Needed so model is installed when tests are run independently:
from django.contrib.auth.tests.custom_user import CustomUser # NOQA from .custom_user import CustomUser # NOQA
from django.contrib.auth.tests.utils import skipIfCustomUser from .settings import AUTH_TEMPLATES
from django.contrib.auth.views import login as login_view from .utils import skipIfCustomUser
@override_settings( @override_settings(
@ -36,10 +35,7 @@ from django.contrib.auth.views import login as login_view
('en', 'English'), ('en', 'English'),
), ),
LANGUAGE_CODE='en', LANGUAGE_CODE='en',
TEMPLATE_LOADERS=global_settings.TEMPLATE_LOADERS, TEMPLATES=AUTH_TEMPLATES,
TEMPLATE_DIRS=(
os.path.join(os.path.dirname(upath(__file__)), 'templates'),
),
USE_TZ=False, USE_TZ=False,
PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',), PASSWORD_HASHERS=('django.contrib.auth.hashers.SHA1PasswordHasher',),
ROOT_URLCONF='django.contrib.auth.tests.urls', ROOT_URLCONF='django.contrib.auth.tests.urls',

View File

@ -781,7 +781,7 @@ TECHNICAL_500_TEMPLATE = ("""
{% endfor %} {% endfor %}
</ul> </ul>
{% else %} {% else %}
<p>Django couldn't find any templates because your <code>TEMPLATE_LOADERS</code> setting is empty!</p> <p>Django couldn't find any templates because your <code>'loaders'</code> option is empty!</p>
{% endif %} {% endif %}
</div> </div>
{% endif %} {% endif %}
@ -900,7 +900,7 @@ Installed Middleware:
{% for loader in loader_debug_info %}Using loader {{ loader.loader }}: {% for loader in loader_debug_info %}Using loader {{ loader.loader }}:
{% for t in loader.templates %}{{ t.name }} ({{ t.status }}) {% for t in loader.templates %}{{ t.name }} ({{ t.status }})
{% endfor %}{% endfor %} {% endfor %}{% endfor %}
{% else %}Django couldn't find any templates because your TEMPLATE_LOADERS setting is empty! {% else %}Django couldn't find any templates because your 'loaders' option is empty!
{% endif %} {% endif %}
{% endif %}{% if template_info %} {% endif %}{% if template_info %}
Template error: Template error:
@ -1091,7 +1091,7 @@ Installed Middleware:
{% for loader in loader_debug_info %}Using loader {{ loader.loader }}: {% for loader in loader_debug_info %}Using loader {{ loader.loader }}:
{% for t in loader.templates %}{{ t.name }} ({{ t.status }}) {% for t in loader.templates %}{{ t.name }} ({{ t.status }})
{% endfor %}{% endfor %} {% endfor %}{% endfor %}
{% else %}Django couldn't find any templates because your TEMPLATE_LOADERS setting is empty! {% else %}Django couldn't find any templates because your 'loaders' option is empty!
{% endif %} {% endif %}
{% endif %}{% if template_info %} {% endif %}{% if template_info %}
Template error: Template error:

View File

@ -178,8 +178,8 @@ processing time.
This helps a lot on virtualized hosts with limited network performance. This helps a lot on virtualized hosts with limited network performance.
:setting:`TEMPLATE_LOADERS` :setting:`TEMPLATES`
--------------------------- --------------------
Enabling the cached template loader often improves performance drastically, as Enabling the cached template loader often improves performance drastically, as
it avoids compiling each template every time it needs to be rendered. See the it avoids compiling each template every time it needs to be rendered. See the

View File

@ -90,6 +90,7 @@ details on these changes.
* The following settings will be removed: * The following settings will be removed:
* ``ALLOWED_INCLUDE_ROOTS`` * ``ALLOWED_INCLUDE_ROOTS``
* ``TEMPLATE_LOADERS``
* ``TEMPLATE_STRING_IF_INVALID`` * ``TEMPLATE_STRING_IF_INVALID``
* The backwards compatibility alias ``django.template.loader.BaseLoader`` will * The backwards compatibility alias ``django.template.loader.BaseLoader`` will

View File

@ -314,12 +314,13 @@ creating a template that the view can use.
First, create a directory called ``templates`` in your ``polls`` directory. First, create a directory called ``templates`` in your ``polls`` directory.
Django will look for templates in there. Django will look for templates in there.
Django's :setting:`TEMPLATE_LOADERS` setting contains a list of callables that Your project's :setting:`TEMPLATES` setting describes how Django will load and
know how to import templates from various sources. One of the defaults is render templates. The default settings file configures a ``DjangoTemplates``
:class:`django.template.loaders.app_directories.Loader` which looks for a backend whose :setting:`APP_DIRS <TEMPLATES-APP_DIRS>` option is set to
"templates" subdirectory in each of the :setting:`INSTALLED_APPS` - this is how ``True``. By convention ``DjangoTemplates`` looks for a "templates"
Django knows to find the polls templates even though we didn't modify subdirectory in each of the :setting:`INSTALLED_APPS`. This is how Django
:setting:`TEMPLATE_DIRS`, as we did in :ref:`Tutorial 2 knows to find the polls templates even though we didn't modify the
:setting:`DIRS <TEMPLATES-DIRS>` option, as we did in :ref:`Tutorial 2
<ref-customizing-your-projects-templates>`. <ref-customizing-your-projects-templates>`.
.. admonition:: Organizing templates .. admonition:: Organizing templates

View File

@ -2337,8 +2337,9 @@ directory.
In order to override one or more of them, first create an ``admin`` directory In order to override one or more of them, first create an ``admin`` directory
in your project's ``templates`` directory. This can be any of the directories in your project's ``templates`` directory. This can be any of the directories
you specified in :setting:`TEMPLATE_DIRS`. If you have customized the you specified in the :setting:`DIRS <TEMPLATES-DIRS>` option of the
:setting:`TEMPLATE_LOADERS` setting, be sure ``DjangoTemplates`` backend in the :setting:`TEMPLATES` setting. If you have
customized the ``'loaders'`` option, be sure
``'django.template.loaders.filesystem.Loader'`` appears before ``'django.template.loaders.filesystem.Loader'`` appears before
``'django.template.loaders.app_directories.Loader'`` so that your custom ``'django.template.loaders.app_directories.Loader'`` so that your custom
templates will be found by the template loading system before those that are templates will be found by the template loading system before those that are

View File

@ -34,9 +34,9 @@ To install the sitemap app, follow these steps:
1. Add ``'django.contrib.sitemaps'`` to your :setting:`INSTALLED_APPS` 1. Add ``'django.contrib.sitemaps'`` to your :setting:`INSTALLED_APPS`
setting. setting.
2. Make sure ``'django.template.loaders.app_directories.Loader'`` 2. Make sure your :setting:`TEMPLATES` setting contains a ``DjangoTemplates``
is in your :setting:`TEMPLATE_LOADERS` setting. It's in there by default, backend whose ``APP_DIRS`` options is set to ``True``. It's in there by
so you'll only need to change this if you've changed that setting. default, so you'll only need to change this if you've changed that setting.
3. Make sure you've installed the 3. Make sure you've installed the
:mod:`sites framework <django.contrib.sites>`. :mod:`sites framework <django.contrib.sites>`.

View File

@ -2439,6 +2439,11 @@ Default::
('django.template.loaders.filesystem.Loader', ('django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader') 'django.template.loaders.app_directories.Loader')
.. deprecated:: 1.8
Set the ``'loaders'`` option in the :setting:`OPTIONS <TEMPLATES-OPTIONS>`
of a ``DjangoTemplates`` backend instead.
A tuple of template loader classes, specified as strings. Each ``Loader`` class A tuple of template loader classes, specified as strings. Each ``Loader`` class
knows how to import templates from a particular source. Optionally, a tuple can be knows how to import templates from a particular source. Optionally, a tuple can be
used instead of a string. The first item in the tuple should be the ``Loader``s used instead of a string. The first item in the tuple should be the ``Loader``s

View File

@ -734,9 +734,10 @@ with a few other template loaders, which know how to load templates from other
sources. sources.
Some of these other loaders are disabled by default, but you can activate them Some of these other loaders are disabled by default, but you can activate them
by editing your :setting:`TEMPLATE_LOADERS` setting. :setting:`TEMPLATE_LOADERS` by adding a ``'loaders'`` option to your ``DjangoTemplates`` backend in the
should be a tuple of strings or tuples, where each represents a template loader :setting:`TEMPLATES` setting. ``'loaders'`` should be a list of strings or
class. Here are the template loaders that come with Django: tuples, where each represents a template loader class. Here are the template
loaders that come with Django:
.. currentmodule:: django.template.loaders .. currentmodule:: django.template.loaders
@ -744,8 +745,16 @@ class. Here are the template loaders that come with Django:
.. class:: filesystem.Loader .. class:: filesystem.Loader
Loads templates from the filesystem, according to :setting:`TEMPLATE_DIRS`. Loads templates from the filesystem, according to
This loader is enabled by default. :setting:`DIRS <TEMPLATES-DIRS>`.
This loader is enabled by default. However it won't find any templates
until you set :setting:`DIRS <TEMPLATES-DIRS>` to a non-empty list::
TEMPLATES = [{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
}]
``django.template.loaders.app_directories.Loader`` ``django.template.loaders.app_directories.Loader``
@ -782,7 +791,14 @@ class. Here are the template loaders that come with Django:
it caches a list of which :setting:`INSTALLED_APPS` packages have a it caches a list of which :setting:`INSTALLED_APPS` packages have a
``templates`` subdirectory. ``templates`` subdirectory.
This loader is enabled by default. This loader is enabled if and only if :setting:`APP_DIRS
<TEMPLATES-APP_DIRS>` is set::
TEMPLATES = [{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'APP_DIRS': True,
}]
``django.template.loaders.eggs.Loader`` ``django.template.loaders.eggs.Loader``
@ -810,12 +826,18 @@ class. Here are the template loaders that come with Django:
For example, to enable template caching with the ``filesystem`` and For example, to enable template caching with the ``filesystem`` and
``app_directories`` template loaders you might use the following settings:: ``app_directories`` template loaders you might use the following settings::
TEMPLATE_LOADERS = ( TEMPLATES = [{
('django.template.loaders.cached.Loader', ( 'BACKEND': 'django.template.backends.django.DjangoTemplates',
'django.template.loaders.filesystem.Loader', 'DIRS': [os.path.join(BASE_DIR, 'templates')],
'django.template.loaders.app_directories.Loader', 'OPTIONS': {
)), 'loaders': [
) ('django.template.loaders.cached.Loader', (
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
)),
],
},
}]
.. note:: .. note::
@ -838,17 +860,21 @@ class. Here are the template loaders that come with Django:
This loader takes a dictionary of templates as its first argument:: This loader takes a dictionary of templates as its first argument::
TEMPLATE_LOADERS = ( TEMPLATES = [{
('django.template.loaders.locmem.Loader', { 'BACKEND': 'django.template.backends.django.DjangoTemplates',
'index.html': 'content here', 'OPTIONS': {
}), 'loaders': [
) ('django.template.loaders.locmem.Loader', {
'index.html': 'content here',
}),
],
},
}]
This loader is disabled by default. This loader is disabled by default.
Django uses the template loaders in order according to the Django uses the template loaders in order according to the ``'loaders'``
:setting:`TEMPLATE_LOADERS` setting. It uses each loader until a loader finds a option. It uses each loader until a loader finds a match.
match.
.. currentmodule:: django.template .. currentmodule:: django.template

View File

@ -267,9 +267,9 @@ opposed to functions, the only method available until Django 1.1.
All the template loaders :ref:`shipped with Django <template-loaders>` have All the template loaders :ref:`shipped with Django <template-loaders>` have
been ported to the new API but they still implement the function-based API and been ported to the new API but they still implement the function-based API and
the template core machinery still accepts function-based loaders (builtin or the template core machinery still accepts function-based loaders (builtin or
third party) so there is no immediate need to modify your third party) so there is no immediate need to modify your ``TEMPLATE_LOADERS``
:setting:`TEMPLATE_LOADERS` setting in existing projects, things will keep setting in existing projects, things will keep working if you leave it
working if you leave it untouched up to and including the Django 1.3 release. untouched up to and including the Django 1.3 release.
If you have developed your own custom template loaders we suggest to consider If you have developed your own custom template loaders we suggest to consider
porting them to a class-based implementation because the code for backwards porting them to a class-based implementation because the code for backwards

View File

@ -917,7 +917,7 @@ Miscellaneous
session store always fetches the most current session data. session store always fetches the most current session data.
* Private APIs ``override_template_loaders`` and ``override_with_test_loader`` * Private APIs ``override_template_loaders`` and ``override_with_test_loader``
in ``django.test.utils`` were removed. Override ``TEMPLATE_LOADERS`` with in ``django.test.utils`` were removed. Override ``TEMPLATES`` with
``override_settings`` instead. ``override_settings`` instead.
* Warnings from the MySQL database backend are no longer converted to * Warnings from the MySQL database backend are no longer converted to
@ -1021,6 +1021,7 @@ As a consequence of the multiple template engines refactor, several settings
are deprecated in favor of :setting:`TEMPLATES`: are deprecated in favor of :setting:`TEMPLATES`:
* ``ALLOWED_INCLUDE_ROOTS`` * ``ALLOWED_INCLUDE_ROOTS``
* ``TEMPLATE_LOADERS``
* ``TEMPLATE_STRING_IF_INVALID`` * ``TEMPLATE_STRING_IF_INVALID``
``django.core.context_processors`` ``django.core.context_processors``

View File

@ -136,10 +136,9 @@ bit is just the lowercased version of the model's name.
.. note:: .. note::
Thus, when (for example) the Thus, when (for example) the ``APP_DIRS`` option of a ``DjangoTemplates``
:class:`django.template.loaders.app_directories.Loader` template loader is backend is set to True in :setting:`TEMPLATES`, a template location could
enabled in :setting:`TEMPLATE_LOADERS`, a template location could be: be: /path/to/project/books/templates/books/publisher_list.html
/path/to/project/books/templates/books/publisher_list.html
This template will be rendered against a context containing a variable called This template will be rendered against a context containing a variable called
``object_list`` that contains all the publisher objects. A very simple template ``object_list`` that contains all the publisher objects. A very simple template

View File

@ -1303,8 +1303,7 @@ Django itself uses this signal to reset various data:
Overridden settings Data reset Overridden settings Data reset
================================ ======================== ================================ ========================
USE_TZ, TIME_ZONE Databases timezone USE_TZ, TIME_ZONE Databases timezone
TEMPLATE_CONTEXT_PROCESSORS Context processors cache TEMPLATES Template engines
TEMPLATE_LOADERS Template loaders cache
SERIALIZATION_MODULES Serializers cache SERIALIZATION_MODULES Serializers cache
LOCALE_PATHS, LANGUAGE_CODE Default translation and loaded translations LOCALE_PATHS, LANGUAGE_CODE Default translation and loaded translations
MEDIA_ROOT, DEFAULT_FILE_STORAGE Default file storage MEDIA_ROOT, DEFAULT_FILE_STORAGE Default file storage

View File

@ -431,14 +431,14 @@ class IsOverriddenTest(TestCase):
s = Settings('fake_settings_module') s = Settings('fake_settings_module')
self.assertTrue(s.is_overridden('SECRET_KEY')) self.assertTrue(s.is_overridden('SECRET_KEY'))
self.assertFalse(s.is_overridden('TEMPLATE_LOADERS')) self.assertFalse(s.is_overridden('ALLOWED_HOSTS'))
finally: finally:
del sys.modules['fake_settings_module'] del sys.modules['fake_settings_module']
def test_override(self): def test_override(self):
self.assertFalse(settings.is_overridden('TEMPLATE_LOADERS')) self.assertFalse(settings.is_overridden('ALLOWED_HOSTS'))
with override_settings(TEMPLATE_LOADERS=[]): with override_settings(ALLOWED_HOSTS=[]):
self.assertTrue(settings.is_overridden('TEMPLATE_LOADERS')) self.assertTrue(settings.is_overridden('ALLOWED_HOSTS'))
class TestTupleSettings(unittest.TestCase): class TestTupleSettings(unittest.TestCase):

View File

@ -16,7 +16,7 @@ except ImportError:
from django.template import TemplateDoesNotExist, Context from django.template import TemplateDoesNotExist, Context
from django.template.loaders.eggs import Loader as EggLoader from django.template.loaders import cached, eggs
from django.template.engine import Engine from django.template.engine import Engine
from django.template import loader from django.template import loader
from django.test import SimpleTestCase, override_settings from django.test import SimpleTestCase, override_settings
@ -26,6 +26,11 @@ from django.utils._os import upath
from django.utils.six import StringIO from django.utils.six import StringIO
TEMPLATES_DIR = os.path.join(os.path.dirname(upath(__file__)), 'templates')
GLOBAL_TEMPLATES_DIR = os.path.join(os.path.dirname(os.path.dirname(upath(__file__))), 'templates')
# Mock classes and objects for pkg_resources functions. # Mock classes and objects for pkg_resources functions.
class MockLoader(object): class MockLoader(object):
pass pass
@ -48,7 +53,10 @@ def create_egg(name, resources):
@unittest.skipUnless(pkg_resources, 'setuptools is not installed') @unittest.skipUnless(pkg_resources, 'setuptools is not installed')
class EggLoaderTest(SimpleTestCase): class EggLoaderTest(SimpleTestCase):
def setUp(self): def setUp(self):
self.loader = eggs.Loader(Engine.get_default())
# Defined here b/c at module scope we may not have pkg_resources # Defined here b/c at module scope we may not have pkg_resources
class MockProvider(pkg_resources.NullProvider): class MockProvider(pkg_resources.NullProvider):
def __init__(self, module): def __init__(self, module):
@ -81,70 +89,64 @@ class EggLoaderTest(SimpleTestCase):
@override_settings(INSTALLED_APPS=['egg_empty']) @override_settings(INSTALLED_APPS=['egg_empty'])
def test_empty(self): def test_empty(self):
"Loading any template on an empty egg should fail" "Loading any template on an empty egg should fail"
egg_loader = EggLoader(Engine.get_default()) with self.assertRaises(TemplateDoesNotExist):
self.assertRaises(TemplateDoesNotExist, egg_loader.load_template_source, "not-existing.html") self.loader.load_template_source("not-existing.html")
@override_settings(INSTALLED_APPS=['egg_1']) @override_settings(INSTALLED_APPS=['egg_1'])
def test_non_existing(self): def test_non_existing(self):
"Template loading fails if the template is not in the egg" "Template loading fails if the template is not in the egg"
egg_loader = EggLoader(Engine.get_default()) with self.assertRaises(TemplateDoesNotExist):
self.assertRaises(TemplateDoesNotExist, egg_loader.load_template_source, "not-existing.html") self.loader.load_template_source("not-existing.html")
@override_settings(INSTALLED_APPS=['egg_1']) @override_settings(INSTALLED_APPS=['egg_1'])
def test_existing(self): def test_existing(self):
"A template can be loaded from an egg" "A template can be loaded from an egg"
egg_loader = EggLoader(Engine.get_default()) contents, template_name = self.loader.load_template_source("y.html")
contents, template_name = egg_loader.load_template_source("y.html")
self.assertEqual(contents, "y") self.assertEqual(contents, "y")
self.assertEqual(template_name, "egg:egg_1:templates/y.html") self.assertEqual(template_name, "egg:egg_1:templates/y.html")
def test_not_installed(self): def test_not_installed(self):
"Loading an existent template from an egg not included in any app should fail" "Loading an existent template from an egg not included in any app should fail"
egg_loader = EggLoader(Engine.get_default()) with self.assertRaises(TemplateDoesNotExist):
self.assertRaises(TemplateDoesNotExist, egg_loader.load_template_source, "y.html") self.loader.load_template_source("y.html")
@override_settings(
TEMPLATE_LOADERS=(
('django.template.loaders.cached.Loader', (
'django.template.loaders.filesystem.Loader',
)),
)
)
class CachedLoader(SimpleTestCase): class CachedLoader(SimpleTestCase):
def setUp(self):
self.loader = cached.Loader(Engine.get_default(), [
'django.template.loaders.filesystem.Loader',
])
def test_templatedir_caching(self): def test_templatedir_caching(self):
"Check that the template directories form part of the template cache key. Refs #13573" "Check that the template directories form part of the template cache key. Refs #13573"
template_loader = Engine.get_default().template_loaders[0]
# Retrieve a template specifying a template directory to check # Retrieve a template specifying a template directory to check
t1, name = template_loader.find_template('test.html', (os.path.join(os.path.dirname(upath(__file__)), 'templates', 'first'),)) t1, name = self.loader.find_template('test.html', (os.path.join(TEMPLATES_DIR, 'first'),))
# Now retrieve the same template name, but from a different directory # Now retrieve the same template name, but from a different directory
t2, name = template_loader.find_template('test.html', (os.path.join(os.path.dirname(upath(__file__)), 'templates', 'second'),)) t2, name = self.loader.find_template('test.html', (os.path.join(TEMPLATES_DIR, 'second'),))
# The two templates should not have the same content # The two templates should not have the same content
self.assertNotEqual(t1.render(Context({})), t2.render(Context({}))) self.assertNotEqual(t1.render(Context({})), t2.render(Context({})))
def test_missing_template_is_cached(self): def test_missing_template_is_cached(self):
"#19949 -- Check that the missing template is cached." "#19949 -- Check that the missing template is cached."
template_loader = Engine.get_default().template_loaders[0]
# Empty cache, which may be filled from previous tests.
template_loader.reset()
# Check that 'missing.html' isn't already in cache before 'missing.html' is loaded # Check that 'missing.html' isn't already in cache before 'missing.html' is loaded
self.assertRaises(KeyError, lambda: template_loader.template_cache["missing.html"]) with self.assertRaises(KeyError):
self.loader.template_cache["missing.html"]
# Try to load it, it should fail # Try to load it, it should fail
self.assertRaises(TemplateDoesNotExist, template_loader.load_template, "missing.html") with self.assertRaises(TemplateDoesNotExist):
self.loader.load_template("missing.html")
# Verify that the fact that the missing template, which hasn't been found, has actually # Verify that the fact that the missing template, which hasn't been found, has actually
# been cached: # been cached:
self.assertEqual(template_loader.template_cache.get("missing.html"), cached_miss = self.loader.template_cache["missing.html"]
TemplateDoesNotExist, self.assertEqual(cached_miss, TemplateDoesNotExist,
"Cached template loader doesn't cache file lookup misses. It should.") "Cached template loader doesn't cache file lookup misses. It should.")
@override_settings( @override_settings(TEMPLATES=[{
TEMPLATE_DIRS=( 'BACKEND': 'django.template.backends.django.DjangoTemplates',
os.path.join(os.path.dirname(upath(__file__)), 'templates'), 'DIRS': [TEMPLATES_DIR],
) }])
)
class RenderToStringTest(SimpleTestCase): class RenderToStringTest(SimpleTestCase):
def test_basic(self): def test_basic(self):
self.assertEqual(loader.render_to_string('test_context.html'), 'obj:\n') self.assertEqual(loader.render_to_string('test_context.html'), 'obj:\n')
@ -164,11 +166,10 @@ class RenderToStringTest(SimpleTestCase):
loader.select_template, []) loader.select_template, [])
@override_settings( @override_settings(TEMPLATES=[{
TEMPLATE_DIRS=( 'BACKEND': 'django.template.backends.django.DjangoTemplates',
os.path.join(os.path.dirname(upath(__file__)), 'templates'), 'DIRS': [TEMPLATES_DIR],
) }])
)
class DeprecatedRenderToStringTest(IgnorePendingDeprecationWarningsMixin, SimpleTestCase): class DeprecatedRenderToStringTest(IgnorePendingDeprecationWarningsMixin, SimpleTestCase):
def test_existing_context_kept_clean(self): def test_existing_context_kept_clean(self):
@ -191,7 +192,10 @@ class DeprecatedRenderToStringTest(IgnorePendingDeprecationWarningsMixin, Simple
loader.render_to_string('test_context_stack.html', context_instance=Context()).strip()) loader.render_to_string('test_context_stack.html', context_instance=Context()).strip())
class TemplateDirsOverrideTest(IgnorePendingDeprecationWarningsMixin, unittest.TestCase): @override_settings(TEMPLATES=[{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
}])
class TemplateDirsOverrideTest(IgnorePendingDeprecationWarningsMixin, SimpleTestCase):
dirs_tuple = (os.path.join(os.path.dirname(upath(__file__)), 'other_templates'),) dirs_tuple = (os.path.join(os.path.dirname(upath(__file__)), 'other_templates'),)
dirs_list = list(dirs_tuple) dirs_list = list(dirs_tuple)
@ -212,14 +216,18 @@ class TemplateDirsOverrideTest(IgnorePendingDeprecationWarningsMixin, unittest.T
self.assertEqual(template.render(Context({})), 'spam eggs\n') self.assertEqual(template.render(Context({})), 'spam eggs\n')
@override_settings( @override_settings(TEMPLATES=[{
TEMPLATE_LOADERS=( 'BACKEND': 'django.template.backends.django.DjangoTemplates',
('django.template.loaders.cached.Loader', ( 'DIRS': [GLOBAL_TEMPLATES_DIR],
'django.template.loaders.filesystem.Loader', 'OPTIONS': {
'django.template.loaders.app_directories.Loader', 'loaders': [
)), ('django.template.loaders.cached.Loader', [
) 'django.template.loaders.filesystem.Loader',
) 'django.template.loaders.app_directories.Loader',
]),
],
},
}])
class PriorityCacheLoader(SimpleTestCase): class PriorityCacheLoader(SimpleTestCase):
def test_basic(self): def test_basic(self):
""" """
@ -229,10 +237,16 @@ class PriorityCacheLoader(SimpleTestCase):
self.assertEqual(t1.render(Context({})), 'priority\n') self.assertEqual(t1.render(Context({})), 'priority\n')
@override_settings( @override_settings(TEMPLATES=[{
TEMPLATE_LOADERS=('django.template.loaders.filesystem.Loader', 'BACKEND': 'django.template.backends.django.DjangoTemplates',
'django.template.loaders.app_directories.Loader',), 'DIRS': [GLOBAL_TEMPLATES_DIR],
) 'OPTIONS': {
'loaders': [
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
],
},
}])
class PriorityLoader(SimpleTestCase): class PriorityLoader(SimpleTestCase):
def test_basic(self): def test_basic(self):
""" """

View File

@ -17,6 +17,11 @@ from django.test.utils import override_settings, extend_sys_path
from django.utils._os import upath from django.utils._os import upath
TESTS_DIR = os.path.dirname(os.path.dirname(os.path.abspath(upath(__file__))))
TEMPLATES_DIR = os.path.join(TESTS_DIR, 'templates')
class TemplateLoaderTests(SimpleTestCase): class TemplateLoaderTests(SimpleTestCase):
def test_loaders_security(self): def test_loaders_security(self):
@ -73,7 +78,10 @@ class TemplateLoaderTests(SimpleTestCase):
test_template_sources('/DIR1/index.HTML', template_dirs, test_template_sources('/DIR1/index.HTML', template_dirs,
['/DIR1/index.HTML']) ['/DIR1/index.HTML'])
@override_settings(TEMPLATE_LOADERS=['django.template.loaders.filesystem.Loader']) @override_settings(TEMPLATES=[{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [TEMPLATES_DIR],
}])
# Turn TEMPLATE_DEBUG on, so that the origin file name will be kept with # Turn TEMPLATE_DEBUG on, so that the origin file name will be kept with
# the compiled templates. # the compiled templates.
@override_settings(TEMPLATE_DEBUG=True) @override_settings(TEMPLATE_DEBUG=True)
@ -90,10 +98,17 @@ class TemplateLoaderTests(SimpleTestCase):
self.assertTrue(template_name.endswith(load_name), self.assertTrue(template_name.endswith(load_name),
'Template loaded by filesystem loader has incorrect name for debug page: %s' % template_name) 'Template loaded by filesystem loader has incorrect name for debug page: %s' % template_name)
@override_settings(TEMPLATE_LOADERS=[ @override_settings(TEMPLATES=[{
('django.template.loaders.cached.Loader', 'BACKEND': 'django.template.backends.django.DjangoTemplates',
['django.template.loaders.filesystem.Loader']), 'DIRS': [TEMPLATES_DIR],
]) 'OPTIONS': {
'loaders': [
('django.template.loaders.cached.Loader', [
'django.template.loaders.filesystem.Loader',
]),
],
},
}])
@override_settings(TEMPLATE_DEBUG=True) @override_settings(TEMPLATE_DEBUG=True)
def test_cached_loader_debug_origin(self): def test_cached_loader_debug_origin(self):
# Same comment as in test_loader_debug_origin. # Same comment as in test_loader_debug_origin.
@ -130,7 +145,10 @@ class TemplateLoaderTests(SimpleTestCase):
# Test the base loader class via the app loader. load_template # Test the base loader class via the app loader. load_template
# from base is used by all shipped loaders excepting cached, # from base is used by all shipped loaders excepting cached,
# which has its own test. # which has its own test.
@override_settings(TEMPLATE_LOADERS=['django.template.loaders.app_directories.Loader']) @override_settings(TEMPLATES=[{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'APP_DIRS': True,
}])
def test_include_missing_template(self): def test_include_missing_template(self):
""" """
Tests that the correct template is identified as not existing Tests that the correct template is identified as not existing
@ -151,7 +169,10 @@ class TemplateLoaderTests(SimpleTestCase):
# Test the base loader class via the app loader. load_template # Test the base loader class via the app loader. load_template
# from base is used by all shipped loaders excepting cached, # from base is used by all shipped loaders excepting cached,
# which has its own test. # which has its own test.
@override_settings(TEMPLATE_LOADERS=['django.template.loaders.app_directories.Loader']) @override_settings(TEMPLATES=[{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'APP_DIRS': True,
}])
def test_extends_include_missing_baseloader(self): def test_extends_include_missing_baseloader(self):
""" """
Tests that the correct template is identified as not existing Tests that the correct template is identified as not existing
@ -168,34 +189,39 @@ class TemplateLoaderTests(SimpleTestCase):
self.assertEqual(e.args[0], 'missing.html') self.assertEqual(e.args[0], 'missing.html')
self.assertEqual(r, None, 'Template rendering unexpectedly succeeded, produced: ->%r<-' % r) self.assertEqual(r, None, 'Template rendering unexpectedly succeeded, produced: ->%r<-' % r)
@override_settings(TEMPLATES=[{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'OPTIONS': {
'loaders': [
('django.template.loaders.cached.Loader', [
'django.template.loaders.app_directories.Loader',
]),
],
},
}])
@override_settings(TEMPLATE_DEBUG=True) @override_settings(TEMPLATE_DEBUG=True)
def test_extends_include_missing_cachedloader(self): def test_extends_include_missing_cachedloader(self):
""" """
Same as test_extends_include_missing_baseloader, only tests Same as test_extends_include_missing_baseloader, only tests
behavior of the cached loader instead of base loader. behavior of the cached loader instead of base loader.
""" """
with override_settings(TEMPLATE_LOADERS=[ load_name = 'test_extends_error.html'
('django.template.loaders.cached.Loader', [ tmpl = loader.get_template(load_name)
'django.template.loaders.app_directories.Loader', r = None
]), try:
]): r = tmpl.render(template.Context({}))
load_name = 'test_extends_error.html' except template.TemplateDoesNotExist as e:
tmpl = loader.get_template(load_name) self.assertEqual(e.args[0], 'missing.html')
r = None self.assertEqual(r, None, 'Template rendering unexpectedly succeeded, produced: ->%r<-' % r)
try:
r = tmpl.render(template.Context({}))
except template.TemplateDoesNotExist as e:
self.assertEqual(e.args[0], 'missing.html')
self.assertEqual(r, None, 'Template rendering unexpectedly succeeded, produced: ->%r<-' % r)
# For the cached loader, repeat the test, to ensure the first attempt did not cache a # For the cached loader, repeat the test, to ensure the first attempt did not cache a
# result that behaves incorrectly on subsequent attempts. # result that behaves incorrectly on subsequent attempts.
tmpl = loader.get_template(load_name) tmpl = loader.get_template(load_name)
try: try:
tmpl.render(template.Context({})) tmpl.render(template.Context({}))
except template.TemplateDoesNotExist as e: except template.TemplateDoesNotExist as e:
self.assertEqual(e.args[0], 'missing.html') self.assertEqual(e.args[0], 'missing.html')
self.assertEqual(r, None, 'Template rendering unexpectedly succeeded, produced: ->%r<-' % r) self.assertEqual(r, None, 'Template rendering unexpectedly succeeded, produced: ->%r<-' % r)
def test_include_template_argument(self): def test_include_template_argument(self):
""" """
@ -429,11 +455,16 @@ class RequestContextTests(unittest.TestCase):
def setUp(self): def setUp(self):
self.fake_request = RequestFactory().get('/') self.fake_request = RequestFactory().get('/')
@override_settings(TEMPLATE_LOADERS=[ @override_settings(TEMPLATES=[{
('django.template.loaders.locmem.Loader', { 'BACKEND': 'django.template.backends.django.DjangoTemplates',
'child': '{{ var|default:"none" }}', 'OPTIONS': {
}), 'loaders': [
]) ('django.template.loaders.locmem.Loader', {
'child': '{{ var|default:"none" }}',
}),
],
},
}])
def test_include_only(self): def test_include_only(self):
""" """
Regression test for #15721, ``{% include %}`` and ``RequestContext`` Regression test for #15721, ``{% include %}`` and ``RequestContext``

View File

@ -63,21 +63,28 @@ class DebugViewTests(TestCase):
response = self.client.get('/raises400/') response = self.client.get('/raises400/')
self.assertContains(response, '<div class="context" id="', status_code=400) self.assertContains(response, '<div class="context" id="', status_code=400)
# Ensure no 403.html template exists to test the default case.
@override_settings(TEMPLATES=[{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
}])
def test_403(self): def test_403(self):
# Ensure no 403.html template exists to test the default case. response = self.client.get('/raises403/')
with override_settings(TEMPLATE_LOADERS=[]): self.assertContains(response, '<h1>403 Forbidden</h1>', status_code=403)
response = self.client.get('/raises403/')
self.assertContains(response, '<h1>403 Forbidden</h1>', status_code=403)
# Set up a test 403.html template.
@override_settings(TEMPLATES=[{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'OPTIONS': {
'loaders': [
('django.template.loaders.locmem.Loader', {
'403.html': 'This is a test template for a 403 error.',
}),
],
},
}])
def test_403_template(self): def test_403_template(self):
# Set up a test 403.html template. response = self.client.get('/raises403/')
with override_settings(TEMPLATE_LOADERS=[ self.assertContains(response, 'test template', status_code=403)
('django.template.loaders.locmem.Loader', {
'403.html': 'This is a test template for a 403 Forbidden error.',
})
]):
response = self.client.get('/raises403/')
self.assertContains(response, 'test template', status_code=403)
def test_404(self): def test_404(self):
response = self.client.get('/raises404/') response = self.client.get('/raises404/')

View File

@ -35,21 +35,26 @@ class DefaultsTests(TestCase):
response = self.client.get('/server_error/') response = self.client.get('/server_error/')
self.assertEqual(response.status_code, 500) self.assertEqual(response.status_code, 500)
@override_settings(TEMPLATES=[{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'OPTIONS': {
'loaders': [
('django.template.loaders.locmem.Loader', {
'404.html': 'This is a test template for a 404 error.',
'500.html': 'This is a test template for a 500 error.',
}),
],
},
}])
def test_custom_templates(self): def test_custom_templates(self):
""" """
Test that 404.html and 500.html templates are picked by their respective Test that 404.html and 500.html templates are picked by their respective
handler. handler.
""" """
with override_settings(TEMPLATE_LOADERS=[ for code, url in ((404, '/non_existing_url/'), (500, '/server_error/')):
('django.template.loaders.locmem.Loader', { response = self.client.get(url)
'404.html': 'This is a test template for a 404 error.', self.assertContains(response, "test template for a %d error" % code,
'500.html': 'This is a test template for a 500 error.', status_code=code)
}),
]):
for code, url in ((404, '/non_existing_url/'), (500, '/server_error/')):
response = self.client.get(url)
self.assertContains(response, "test template for a %d error" % code,
status_code=code)
def test_get_absolute_url_attributes(self): def test_get_absolute_url_attributes(self):
"A model can set attributes on the get_absolute_url method" "A model can set attributes on the get_absolute_url method"