From 6b3724fa1116c0949a6e0cd3e0dd55959a3abd93 Mon Sep 17 00:00:00 2001
From: Carlton Gibson <carlton.gibson@noumenal.co.uk>
Date: Fri, 10 Mar 2017 21:46:37 +0100
Subject: [PATCH] Fixed #27359 -- Made Engine.get_default() return the first
 DjangoTemplates engine if multiple are defined.

---
 AUTHORS                             |  1 +
 django/template/engine.py           | 21 ++++++---------------
 docs/ref/templates/api.txt          | 20 ++++++++++++++------
 docs/releases/2.0.txt               |  4 +++-
 tests/template_tests/test_engine.py |  6 +++---
 5 files changed, 27 insertions(+), 25 deletions(-)

diff --git a/AUTHORS b/AUTHORS
index 5524ea9ca4..0ab2376643 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -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>
diff --git a/django/template/engine.py b/django/template/engine.py
index e10e8f0078..381d656bbb 100644
--- a/django/template/engine.py
+++ b/django/template/engine.py
@@ -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):
diff --git a/docs/ref/templates/api.txt b/docs/ref/templates/api.txt
index 2efbedbdc2..e8d140910d 100644
--- a/docs/ref/templates/api.txt
+++ b/docs/ref/templates/api.txt
@@ -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
 
diff --git a/docs/releases/2.0.txt b/docs/releases/2.0.txt
index 369a5893ba..ee2117546b 100644
--- a/docs/releases/2.0.txt
+++ b/docs/releases/2.0.txt
@@ -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
 ~~~~~
diff --git a/tests/template_tests/test_engine.py b/tests/template_tests/test_engine.py
index 2ed28e6ce4..2bb8601fbb 100644
--- a/tests/template_tests/test_engine.py
+++ b/tests/template_tests/test_engine.py
@@ -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):