Fixed #27359 -- Made Engine.get_default() return the first DjangoTemplates engine if multiple are defined.

This commit is contained in:
Carlton Gibson 2017-03-10 21:46:37 +01:00 committed by Tim Graham
parent 7019724101
commit 6b3724fa11
5 changed files with 27 additions and 25 deletions

View File

@ -141,6 +141,7 @@ answer newbie questions, and generally made Django that much better:
Carl Meyer <carl@oddbird.net>
Carlos Eduardo de Paula <carlosedp@gmail.com>
Carlos Matías de la Torre <cmdelatorre@gmail.com>
Carlton Gibson <carlton.gibson@noumenal.es>
cedric@terramater.net
ChaosKCW
Charlie Leifer <coleifer@gmail.com>

View File

@ -56,9 +56,8 @@ class Engine:
@functools.lru_cache()
def get_default():
"""
When only one DjangoTemplates backend is configured, return it.
Raise ImproperlyConfigured otherwise.
Return the first DjangoTemplates backend that's configured, or raise
ImproperlyConfigured if none are configured.
This is required for preserving historical APIs that rely on a
globally available, implicitly configured engine such as:
@ -74,18 +73,10 @@ class Engine:
# local imports are required to avoid import loops.
from django.template import engines
from django.template.backends.django import DjangoTemplates
django_engines = [engine for engine in engines.all()
if isinstance(engine, DjangoTemplates)]
if len(django_engines) == 1:
# Unwrap the Engine instance inside DjangoTemplates
return django_engines[0].engine
elif len(django_engines) == 0:
raise ImproperlyConfigured(
"No DjangoTemplates backend is configured.")
else:
raise ImproperlyConfigured(
"Several DjangoTemplates backends are configured. "
"You must select one explicitly.")
for engine in engines.all():
if isinstance(engine, DjangoTemplates):
return engine.engine
raise ImproperlyConfigured('No DjangoTemplates backend is configured.')
@cached_property
def template_context_processors(self):

View File

@ -146,14 +146,20 @@ what's passed by :class:`~django.template.backends.django.DjangoTemplates`.
.. staticmethod:: Engine.get_default()
When a Django project configures one and only one
:class:`~django.template.backends.django.DjangoTemplates` engine, this
method returns the underlying :class:`Engine`. In other circumstances it
will raise :exc:`~django.core.exceptions.ImproperlyConfigured`.
Returns the underlying :class:`Engine` from the first configured
:class:`~django.template.backends.django.DjangoTemplates` engine. Raises
:exc:`~django.core.exceptions.ImproperlyConfigured` if no engines are
configured.
It's required for preserving APIs that rely on a globally available,
implicitly configured engine. Any other use is strongly discouraged.
.. versionchanged:: 2.0
In older versions, raises
:exc:`~django.core.exceptions.ImproperlyConfigured` if multiple
engines are configured rather than returning the first engine.
.. method:: Engine.from_string(template_code)
Compiles the given template code and returns a :class:`Template` object.
@ -175,9 +181,11 @@ The recommended way to create a :class:`Template` is by calling the factory
methods of the :class:`Engine`: :meth:`~Engine.get_template`,
:meth:`~Engine.select_template` and :meth:`~Engine.from_string`.
In a Django project where the :setting:`TEMPLATES` setting defines exactly one
In a Django project where the :setting:`TEMPLATES` setting defines a
:class:`~django.template.backends.django.DjangoTemplates` engine, it's
possible to instantiate a :class:`Template` directly.
possible to instantiate a :class:`Template` directly. If more than one
:class:`~django.template.backends.django.DjangoTemplates` engine is defined,
the first one will be used.
.. class:: Template

View File

@ -191,7 +191,9 @@ Signals
Templates
~~~~~~~~~
* ...
* To increase the usefulness of :meth:`.Engine.get_default` in third-party
apps, it now returns the first engine if multiple ``DjangoTemplates`` engines
are configured in ``TEMPLATES`` rather than raising ``ImproperlyConfigured``.
Tests
~~~~~

View File

@ -41,14 +41,14 @@ class GetDefaultTests(SimpleTestCase):
@override_settings(TEMPLATES=[{
'NAME': 'default',
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'OPTIONS': {'file_charset': 'abc'},
}, {
'NAME': 'other',
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'OPTIONS': {'file_charset': 'def'},
}])
def test_multiple_engines_configured(self):
msg = 'Several DjangoTemplates backends are configured. You must select one explicitly.'
with self.assertRaisesMessage(ImproperlyConfigured, msg):
Engine.get_default()
self.assertEqual(Engine.get_default().file_charset, 'abc')
class LoaderTests(SimpleTestCase):