summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAymeric Augustin <aymeric.augustin@m4x.org>2015-01-26 21:57:10 +0100
committerAymeric Augustin <aymeric.augustin@m4x.org>2015-02-03 08:29:45 +0100
commit2133f3157eff853329bafb7fda74c3c8fb4eae42 (patch)
tree5bb262ab847c79b3f70d8a8888e267b2816b0373
parenta53541852d5601232899e54d66e623bc163c6dc2 (diff)
Fixed #24168 -- Allowed selecting a template engine in a few APIs.
Specifically in rendering shortcuts, template responses, and class-based views that return template responses. Also added a test for render_to_response(status=...) which was missing from fdbfc980. Thanks Tim and Carl for the review.
-rw-r--r--django/shortcuts.py16
-rw-r--r--django/template/response.py13
-rw-r--r--django/test/utils.py24
-rw-r--r--django/views/generic/base.py2
-rw-r--r--docs/ref/class-based-views/flattened-index.txt14
-rw-r--r--docs/ref/class-based-views/mixins-simple.txt9
-rw-r--r--docs/ref/template-response.txt20
-rw-r--r--docs/topics/http/shortcuts.txt18
-rw-r--r--tests/generic_views/jinja2/generic_views/using.html1
-rw-r--r--tests/generic_views/templates/generic_views/using.html1
-rw-r--r--tests/generic_views/test_base.py16
-rw-r--r--tests/shortcuts/jinja2/shortcuts/using.html1
-rw-r--r--tests/shortcuts/templates/shortcuts/using.html1
-rw-r--r--tests/shortcuts/tests.py24
-rw-r--r--tests/shortcuts/urls.py3
-rw-r--r--tests/shortcuts/views.py17
-rw-r--r--tests/template_tests/jinja2/template_tests/using.html1
-rw-r--r--tests/template_tests/templates/template_tests/using.html1
-rw-r--r--tests/template_tests/test_response.py20
19 files changed, 180 insertions, 22 deletions
diff --git a/django/shortcuts.py b/django/shortcuts.py
index 3bb2412526..bbfc99299f 100644
--- a/django/shortcuts.py
+++ b/django/shortcuts.py
@@ -25,7 +25,7 @@ from django.utils.functional import Promise
def render_to_response(template_name, context=None,
context_instance=_context_instance_undefined,
content_type=None, status=None, dirs=_dirs_undefined,
- dictionary=_dictionary_undefined):
+ dictionary=_dictionary_undefined, using=None):
"""
Returns a HttpResponse whose content is filled with the result of calling
django.template.loader.render_to_string() with the passed arguments.
@@ -34,12 +34,13 @@ def render_to_response(template_name, context=None,
and dirs is _dirs_undefined
and dictionary is _dictionary_undefined):
# No deprecated arguments were passed - use the new code path
- content = loader.render_to_string(template_name, context)
+ content = loader.render_to_string(template_name, context, using=using)
else:
# Some deprecated arguments were passed - use the legacy code path
content = loader.render_to_string(
- template_name, context, context_instance, dirs, dictionary)
+ template_name, context, context_instance, dirs, dictionary,
+ using=using)
return HttpResponse(content, content_type, status)
@@ -47,7 +48,8 @@ def render_to_response(template_name, context=None,
def render(request, template_name, context=None,
context_instance=_context_instance_undefined,
content_type=None, status=None, current_app=_current_app_undefined,
- dirs=_dirs_undefined, dictionary=_dictionary_undefined):
+ dirs=_dirs_undefined, dictionary=_dictionary_undefined,
+ using=None):
"""
Returns a HttpResponse whose content is filled with the result of calling
django.template.loader.render_to_string() with the passed arguments.
@@ -59,7 +61,8 @@ def render(request, template_name, context=None,
and dictionary is _dictionary_undefined):
# No deprecated arguments were passed - use the new code path
# In Django 2.0, request should become a positional argument.
- content = loader.render_to_string(template_name, context, request=request)
+ content = loader.render_to_string(
+ template_name, context, request=request, using=using)
else:
# Some deprecated arguments were passed - use the legacy code path
@@ -80,7 +83,8 @@ def render(request, template_name, context=None,
context_instance._current_app = current_app
content = loader.render_to_string(
- template_name, context, context_instance, dirs, dictionary)
+ template_name, context, context_instance, dirs, dictionary,
+ using=using)
return HttpResponse(content, content_type, status)
diff --git a/django/template/response.py b/django/template/response.py
index ab9559853a..48295c5e05 100644
--- a/django/template/response.py
+++ b/django/template/response.py
@@ -16,7 +16,7 @@ class SimpleTemplateResponse(HttpResponse):
rendering_attrs = ['template_name', 'context_data', '_post_render_callbacks']
def __init__(self, template, context=None, content_type=None, status=None,
- charset=None):
+ charset=None, using=None):
if isinstance(template, Template):
warnings.warn(
"{}'s template argument cannot be a django.template.Template "
@@ -31,6 +31,8 @@ class SimpleTemplateResponse(HttpResponse):
self.template_name = template
self.context_data = context
+ self.using = using
+
self._post_render_callbacks = []
# _request stores the current request object in subclasses that know
@@ -73,9 +75,9 @@ class SimpleTemplateResponse(HttpResponse):
def resolve_template(self, template):
"Accepts a template object, path-to-template or list of paths"
if isinstance(template, (list, tuple)):
- return loader.select_template(template)
+ return loader.select_template(template, using=self.using)
elif isinstance(template, six.string_types):
- return loader.get_template(template)
+ return loader.get_template(template, using=self.using)
else:
return template
@@ -189,7 +191,8 @@ class TemplateResponse(SimpleTemplateResponse):
rendering_attrs = SimpleTemplateResponse.rendering_attrs + ['_request', '_current_app']
def __init__(self, request, template, context=None, content_type=None,
- status=None, current_app=_current_app_undefined, charset=None):
+ status=None, current_app=_current_app_undefined, charset=None,
+ using=None):
# As a convenience we'll allow callers to provide current_app without
# having to avoid needing to create the RequestContext directly
if current_app is not _current_app_undefined:
@@ -199,5 +202,5 @@ class TemplateResponse(SimpleTemplateResponse):
RemovedInDjango20Warning, stacklevel=2)
request.current_app = current_app
super(TemplateResponse, self).__init__(
- template, context, content_type, status, charset)
+ template, context, content_type, status, charset, using)
self._request = request
diff --git a/django/test/utils.py b/django/test/utils.py
index 1991602293..f0d8993a40 100644
--- a/django/test/utils.py
+++ b/django/test/utils.py
@@ -3,7 +3,7 @@ import logging
import re
import sys
import time
-from unittest import skipUnless
+from unittest import skipIf, skipUnless
import warnings
from functools import wraps
from xml.dom.minidom import parseString, Node
@@ -20,6 +20,11 @@ from django.utils import six
from django.utils.encoding import force_str
from django.utils.translation import deactivate
+try:
+ import jinja2
+except ImportError:
+ jinja2 = None
+
__all__ = (
'Approximate', 'ContextList', 'get_runner',
@@ -573,3 +578,20 @@ def freeze_time(t):
yield
finally:
time.time = _real_time
+
+
+def require_jinja2(test_func):
+ """
+ Decorator to enable a Jinja2 template engine in addition to the regular
+ Django template engine for a test or skip it if Jinja2 isn't available.
+ """
+ test_func = skipIf(jinja2 is None, "this test requires jinja2")(test_func)
+ test_func = override_settings(TEMPLATES=[{
+ 'BACKEND': 'django.template.backends.django.DjangoTemplates',
+ 'APP_DIRS': True,
+ }, {
+ 'BACKEND': 'django.template.backends.jinja2.Jinja2',
+ 'APP_DIRS': True,
+ 'OPTIONS': {'keep_trailing_newline': True},
+ }])(test_func)
+ return test_func
diff --git a/django/views/generic/base.py b/django/views/generic/base.py
index a873f11f05..88b6608fd2 100644
--- a/django/views/generic/base.py
+++ b/django/views/generic/base.py
@@ -114,6 +114,7 @@ class TemplateResponseMixin(object):
A mixin that can be used to render a template.
"""
template_name = None
+ template_engine = None
response_class = TemplateResponse
content_type = None
@@ -130,6 +131,7 @@ class TemplateResponseMixin(object):
request=self.request,
template=self.get_template_names(),
context=context,
+ using=self.template_engine,
**response_kwargs
)
diff --git a/docs/ref/class-based-views/flattened-index.txt b/docs/ref/class-based-views/flattened-index.txt
index 8f7c743dd4..5af8a4e7f9 100644
--- a/docs/ref/class-based-views/flattened-index.txt
+++ b/docs/ref/class-based-views/flattened-index.txt
@@ -35,6 +35,7 @@ TemplateView
* :attr:`~django.views.generic.base.TemplateResponseMixin.content_type`
* :attr:`~django.views.generic.base.View.http_method_names`
* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class` [:meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`]
+* :attr:`~django.views.generic.base.TemplateResponseMixin.template_engine`
* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
**Methods**
@@ -89,6 +90,7 @@ DetailView
* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class` [:meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`]
* :attr:`~django.views.generic.detail.SingleObjectMixin.slug_field` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_slug_field`]
* :attr:`~django.views.generic.detail.SingleObjectMixin.slug_url_kwarg`
+* :attr:`~django.views.generic.base.TemplateResponseMixin.template_engine`
* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
* :attr:`~django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_field`
* :attr:`~django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_suffix`
@@ -124,6 +126,7 @@ ListView
* :attr:`~django.views.generic.list.MultipleObjectMixin.paginator_class`
* :attr:`~django.views.generic.list.MultipleObjectMixin.queryset` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_queryset`]
* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class` [:meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`]
+* :attr:`~django.views.generic.base.TemplateResponseMixin.template_engine`
* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
* :attr:`~django.views.generic.list.MultipleObjectTemplateResponseMixin.template_name_suffix`
@@ -155,6 +158,7 @@ FormView
* :attr:`~django.views.generic.edit.FormMixin.prefix` [:meth:`~django.views.generic.edit.FormMixin.get_prefix`]
* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class` [:meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`]
* :attr:`~django.views.generic.edit.FormMixin.success_url` [:meth:`~django.views.generic.edit.FormMixin.get_success_url`]
+* :attr:`~django.views.generic.base.TemplateResponseMixin.template_engine`
* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
**Methods**
@@ -191,6 +195,7 @@ CreateView
* :attr:`~django.views.generic.detail.SingleObjectMixin.slug_field` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_slug_field`]
* :attr:`~django.views.generic.detail.SingleObjectMixin.slug_url_kwarg`
* :attr:`~django.views.generic.edit.FormMixin.success_url` [:meth:`~django.views.generic.edit.FormMixin.get_success_url`]
+* :attr:`~django.views.generic.base.TemplateResponseMixin.template_engine`
* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
* :attr:`~django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_field`
* :attr:`~django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_suffix`
@@ -232,6 +237,7 @@ UpdateView
* :attr:`~django.views.generic.detail.SingleObjectMixin.slug_field` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_slug_field`]
* :attr:`~django.views.generic.detail.SingleObjectMixin.slug_url_kwarg`
* :attr:`~django.views.generic.edit.FormMixin.success_url` [:meth:`~django.views.generic.edit.FormMixin.get_success_url`]
+* :attr:`~django.views.generic.base.TemplateResponseMixin.template_engine`
* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
* :attr:`~django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_field`
* :attr:`~django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_suffix`
@@ -269,6 +275,7 @@ DeleteView
* :attr:`~django.views.generic.detail.SingleObjectMixin.slug_field` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_slug_field`]
* :attr:`~django.views.generic.detail.SingleObjectMixin.slug_url_kwarg`
* :attr:`~django.views.generic.edit.DeletionMixin.success_url` [:meth:`~django.views.generic.edit.DeletionMixin.get_success_url`]
+* :attr:`~django.views.generic.base.TemplateResponseMixin.template_engine`
* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
* :attr:`~django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_field`
* :attr:`~django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_suffix`
@@ -308,6 +315,7 @@ ArchiveIndexView
* :attr:`~django.views.generic.list.MultipleObjectMixin.paginator_class`
* :attr:`~django.views.generic.list.MultipleObjectMixin.queryset` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_queryset`]
* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class` [:meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`]
+* :attr:`~django.views.generic.base.TemplateResponseMixin.template_engine`
* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
* :attr:`~django.views.generic.list.MultipleObjectTemplateResponseMixin.template_name_suffix`
@@ -346,6 +354,7 @@ YearArchiveView
* :attr:`~django.views.generic.list.MultipleObjectMixin.paginator_class`
* :attr:`~django.views.generic.list.MultipleObjectMixin.queryset` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_queryset`]
* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class` [:meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`]
+* :attr:`~django.views.generic.base.TemplateResponseMixin.template_engine`
* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
* :attr:`~django.views.generic.list.MultipleObjectTemplateResponseMixin.template_name_suffix`
* :attr:`~django.views.generic.dates.YearMixin.year` [:meth:`~django.views.generic.dates.YearMixin.get_year`]
@@ -387,6 +396,7 @@ MonthArchiveView
* :attr:`~django.views.generic.list.MultipleObjectMixin.paginator_class`
* :attr:`~django.views.generic.list.MultipleObjectMixin.queryset` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_queryset`]
* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class` [:meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`]
+* :attr:`~django.views.generic.base.TemplateResponseMixin.template_engine`
* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
* :attr:`~django.views.generic.list.MultipleObjectTemplateResponseMixin.template_name_suffix`
* :attr:`~django.views.generic.dates.YearMixin.year` [:meth:`~django.views.generic.dates.YearMixin.get_year`]
@@ -428,6 +438,7 @@ WeekArchiveView
* :attr:`~django.views.generic.list.MultipleObjectMixin.paginator_class`
* :attr:`~django.views.generic.list.MultipleObjectMixin.queryset` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_queryset`]
* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class` [:meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`]
+* :attr:`~django.views.generic.base.TemplateResponseMixin.template_engine`
* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
* :attr:`~django.views.generic.list.MultipleObjectTemplateResponseMixin.template_name_suffix`
* :attr:`~django.views.generic.dates.WeekMixin.week` [:meth:`~django.views.generic.dates.WeekMixin.get_week`]
@@ -473,6 +484,7 @@ DayArchiveView
* :attr:`~django.views.generic.list.MultipleObjectMixin.paginator_class`
* :attr:`~django.views.generic.list.MultipleObjectMixin.queryset` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_queryset`]
* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class` [:meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`]
+* :attr:`~django.views.generic.base.TemplateResponseMixin.template_engine`
* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
* :attr:`~django.views.generic.list.MultipleObjectTemplateResponseMixin.template_name_suffix`
* :attr:`~django.views.generic.dates.YearMixin.year` [:meth:`~django.views.generic.dates.YearMixin.get_year`]
@@ -520,6 +532,7 @@ TodayArchiveView
* :attr:`~django.views.generic.list.MultipleObjectMixin.paginator_class`
* :attr:`~django.views.generic.list.MultipleObjectMixin.queryset` [:meth:`~django.views.generic.list.MultipleObjectMixin.get_queryset`]
* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class` [:meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`]
+* :attr:`~django.views.generic.base.TemplateResponseMixin.template_engine`
* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
* :attr:`~django.views.generic.list.MultipleObjectTemplateResponseMixin.template_name_suffix`
* :attr:`~django.views.generic.dates.YearMixin.year` [:meth:`~django.views.generic.dates.YearMixin.get_year`]
@@ -565,6 +578,7 @@ DateDetailView
* :attr:`~django.views.generic.base.TemplateResponseMixin.response_class` [:meth:`~django.views.generic.base.TemplateResponseMixin.render_to_response`]
* :attr:`~django.views.generic.detail.SingleObjectMixin.slug_field` [:meth:`~django.views.generic.detail.SingleObjectMixin.get_slug_field`]
* :attr:`~django.views.generic.detail.SingleObjectMixin.slug_url_kwarg`
+* :attr:`~django.views.generic.base.TemplateResponseMixin.template_engine`
* :attr:`~django.views.generic.base.TemplateResponseMixin.template_name` [:meth:`~django.views.generic.base.TemplateResponseMixin.get_template_names`]
* :attr:`~django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_field`
* :attr:`~django.views.generic.detail.SingleObjectTemplateResponseMixin.template_name_suffix`
diff --git a/docs/ref/class-based-views/mixins-simple.txt b/docs/ref/class-based-views/mixins-simple.txt
index ce2bd2f3aa..ba18a1325b 100644
--- a/docs/ref/class-based-views/mixins-simple.txt
+++ b/docs/ref/class-based-views/mixins-simple.txt
@@ -49,6 +49,15 @@ TemplateResponseMixin
a ``template_name`` will raise a
:class:`django.core.exceptions.ImproperlyConfigured` exception.
+ .. attribute:: template_engine
+
+ .. versionadded:: 1.8
+
+ The :setting:`NAME <TEMPLATES-NAME>` of a template engine to use for
+ loading the template. ``template_engine`` is passed as the ``using``
+ keyword argument to ``response_class``. Default is ``None``, which
+ tells Django to search for the template in all configured engines.
+
.. attribute:: response_class
The response class to be returned by ``render_to_response`` method.
diff --git a/docs/ref/template-response.txt b/docs/ref/template-response.txt
index c1ae0267a5..ecf984cdf3 100644
--- a/docs/ref/template-response.txt
+++ b/docs/ref/template-response.txt
@@ -65,7 +65,7 @@ Attributes
Methods
-------
-.. method:: SimpleTemplateResponse.__init__(template, context=None, content_type=None, status=None, charset=None)
+.. method:: SimpleTemplateResponse.__init__(template, context=None, content_type=None, status=None, charset=None, using=None)
Instantiates a :class:`~django.template.response.SimpleTemplateResponse`
object with the given template, context, content type, HTTP status, and
@@ -102,9 +102,13 @@ Methods
be extracted from ``content_type``, and if that is unsuccessful, the
:setting:`DEFAULT_CHARSET` setting will be used.
- .. versionadded:: 1.8
+ ``using``
+ The :setting:`NAME <TEMPLATES-NAME>` of a template engine to use for
+ loading the template.
- The ``charset`` parameter was added.
+ .. versionchanged:: 1.8
+
+ The ``charset`` and ``using`` parameters were added.
.. method:: SimpleTemplateResponse.resolve_context(context)
@@ -185,7 +189,7 @@ TemplateResponse objects
Methods
-------
-.. method:: TemplateResponse.__init__(request, template, context=None, content_type=None, status=None, current_app=None, charset=None)
+.. method:: TemplateResponse.__init__(request, template, context=None, content_type=None, status=None, current_app=None, charset=None, using=None)
Instantiates a :class:`~django.template.response.TemplateResponse` object
with the given request, template, context, content type, HTTP status, and
@@ -235,9 +239,13 @@ Methods
be extracted from ``content_type``, and if that is unsuccessful, the
:setting:`DEFAULT_CHARSET` setting will be used.
- .. versionadded:: 1.8
+ ``using``
+ The :setting:`NAME <TEMPLATES-NAME>` of a template engine to use for
+ loading the template.
+
+ .. versionchanged:: 1.8
- The ``charset`` parameter was added.
+ The ``charset`` and ``using`` parameters were added.
The rendering process
=====================
diff --git a/docs/topics/http/shortcuts.txt b/docs/topics/http/shortcuts.txt
index 957f042d12..b2c5da3666 100644
--- a/docs/topics/http/shortcuts.txt
+++ b/docs/topics/http/shortcuts.txt
@@ -15,7 +15,7 @@ introduce controlled coupling for convenience's sake.
``render``
==========
-.. function:: render(request, template_name[, context][, context_instance][, content_type][, status][, current_app][, dirs])
+.. function:: render(request, template_name[, context][, context_instance][, content_type][, status][, current_app][, dirs][, using])
Combines a given template with a given context dictionary and returns an
:class:`~django.http.HttpResponse` object with that rendered text.
@@ -77,6 +77,14 @@ Optional arguments
The ``current_app`` argument is deprecated. Instead you should set
``request.current_app``.
+``using``
+ The :setting:`NAME <TEMPLATES-NAME>` of a template engine to use for
+ loading the template.
+
+.. versionchanged:: 1.8
+
+ The ``using`` parameter was added.
+
.. deprecated:: 1.8
The ``dirs`` parameter was deprecated.
@@ -109,7 +117,7 @@ This example is equivalent to::
``render_to_response``
======================
-.. function:: render_to_response(template_name[, context][, context_instance][, content_type][, status][, dirs])
+.. function:: render_to_response(template_name[, context][, context_instance][, content_type][, status][, dirs][, using])
Renders a given template with a given context dictionary and returns an
:class:`~django.http.HttpResponse` object with that rendered text.
@@ -159,9 +167,13 @@ Optional arguments
``status``
The status code for the response. Defaults to ``200``.
+``using``
+ The :setting:`NAME <TEMPLATES-NAME>` of a template engine to use for
+ loading the template.
+
.. versionchanged:: 1.8
- The ``status`` parameter was added.
+ The ``status`` and ``using`` parameters were added.
.. deprecated:: 1.8
diff --git a/tests/generic_views/jinja2/generic_views/using.html b/tests/generic_views/jinja2/generic_views/using.html
new file mode 100644
index 0000000000..8ce973e958
--- /dev/null
+++ b/tests/generic_views/jinja2/generic_views/using.html
@@ -0,0 +1 @@
+Jinja2
diff --git a/tests/generic_views/templates/generic_views/using.html b/tests/generic_views/templates/generic_views/using.html
new file mode 100644
index 0000000000..65bcbf65a4
--- /dev/null
+++ b/tests/generic_views/templates/generic_views/using.html
@@ -0,0 +1 @@
+DTL
diff --git a/tests/generic_views/test_base.py b/tests/generic_views/test_base.py
index 47518fdd92..f297b2e91b 100644
--- a/tests/generic_views/test_base.py
+++ b/tests/generic_views/test_base.py
@@ -7,6 +7,7 @@ from django.core.exceptions import ImproperlyConfigured
from django.core.urlresolvers import resolve
from django.http import HttpResponse
from django.test import TestCase, RequestFactory, override_settings
+from django.test.utils import require_jinja2
from django.views.generic import View, TemplateView, RedirectView
from . import views
@@ -278,10 +279,23 @@ class TemplateViewTest(TestCase):
def test_template_name_required(self):
"""
- A template view must provide a template name
+ A template view must provide a template name.
"""
self.assertRaises(ImproperlyConfigured, self.client.get, '/template/no_template/')
+ @require_jinja2
+ def test_template_engine(self):
+ """
+ A template view may provide a template engine.
+ """
+ request = self.rf.get('/using/')
+ view = TemplateView.as_view(template_name='generic_views/using.html')
+ self.assertEqual(view(request).render().content, b'DTL\n')
+ view = TemplateView.as_view(template_name='generic_views/using.html', template_engine='django')
+ self.assertEqual(view(request).render().content, b'DTL\n')
+ view = TemplateView.as_view(template_name='generic_views/using.html', template_engine='jinja2')
+ self.assertEqual(view(request).render().content, b'Jinja2\n')
+
def test_template_params(self):
"""
A generic template view passes kwargs as context.
diff --git a/tests/shortcuts/jinja2/shortcuts/using.html b/tests/shortcuts/jinja2/shortcuts/using.html
new file mode 100644
index 0000000000..8ce973e958
--- /dev/null
+++ b/tests/shortcuts/jinja2/shortcuts/using.html
@@ -0,0 +1 @@
+Jinja2
diff --git a/tests/shortcuts/templates/shortcuts/using.html b/tests/shortcuts/templates/shortcuts/using.html
new file mode 100644
index 0000000000..65bcbf65a4
--- /dev/null
+++ b/tests/shortcuts/templates/shortcuts/using.html
@@ -0,0 +1 @@
+DTL
diff --git a/tests/shortcuts/tests.py b/tests/shortcuts/tests.py
index e22cf4d386..98251244c5 100644
--- a/tests/shortcuts/tests.py
+++ b/tests/shortcuts/tests.py
@@ -1,5 +1,6 @@
from django.utils.deprecation import RemovedInDjango20Warning
from django.test import TestCase, ignore_warnings, override_settings
+from django.test.utils import require_jinja2
@override_settings(
@@ -38,6 +39,20 @@ class ShortcutTests(TestCase):
self.assertEqual(response.content, b'spam eggs\n')
self.assertEqual(response['Content-Type'], 'text/html; charset=utf-8')
+ def test_render_to_response_with_status(self):
+ response = self.client.get('/render_to_response/status/')
+ self.assertEqual(response.status_code, 403)
+ self.assertEqual(response.content, b'FOO.BAR..\n')
+
+ @require_jinja2
+ def test_render_to_response_with_using(self):
+ response = self.client.get('/render_to_response/using/')
+ self.assertEqual(response.content, b'DTL\n')
+ response = self.client.get('/render_to_response/using/?using=django')
+ self.assertEqual(response.content, b'DTL\n')
+ response = self.client.get('/render_to_response/using/?using=jinja2')
+ self.assertEqual(response.content, b'Jinja2\n')
+
@ignore_warnings(category=RemovedInDjango20Warning)
def test_render_to_response_with_context_instance_misuse(self):
"""
@@ -78,6 +93,15 @@ class ShortcutTests(TestCase):
self.assertEqual(response.status_code, 403)
self.assertEqual(response.content, b'FOO.BAR../render/status/\n')
+ @require_jinja2
+ def test_render_with_using(self):
+ response = self.client.get('/render/using/')
+ self.assertEqual(response.content, b'DTL\n')
+ response = self.client.get('/render/using/?using=django')
+ self.assertEqual(response.content, b'DTL\n')
+ response = self.client.get('/render/using/?using=jinja2')
+ self.assertEqual(response.content, b'Jinja2\n')
+
@ignore_warnings(category=RemovedInDjango20Warning)
def test_render_with_current_app(self):
response = self.client.get('/render/current_app/')
diff --git a/tests/shortcuts/urls.py b/tests/shortcuts/urls.py
index cbb6c99c14..449a840f73 100644
--- a/tests/shortcuts/urls.py
+++ b/tests/shortcuts/urls.py
@@ -8,6 +8,8 @@ urlpatterns = [
url(r'^render_to_response/request_context/$', views.render_to_response_view_with_request_context),
url(r'^render_to_response/content_type/$', views.render_to_response_view_with_content_type),
url(r'^render_to_response/dirs/$', views.render_to_response_view_with_dirs),
+ url(r'^render_to_response/status/$', views.render_to_response_view_with_status),
+ url(r'^render_to_response/using/$', views.render_to_response_view_with_using),
url(r'^render_to_response/context_instance_misuse/$', views.render_to_response_with_context_instance_misuse),
url(r'^render/$', views.render_view),
url(r'^render/multiple_templates/$', views.render_view_with_multiple_templates),
@@ -15,6 +17,7 @@ urlpatterns = [
url(r'^render/content_type/$', views.render_view_with_content_type),
url(r'^render/dirs/$', views.render_with_dirs),
url(r'^render/status/$', views.render_view_with_status),
+ url(r'^render/using/$', views.render_view_with_using),
url(r'^render/current_app/$', views.render_view_with_current_app),
url(r'^render/current_app_conflict/$', views.render_view_with_current_app_conflict),
]
diff --git a/tests/shortcuts/views.py b/tests/shortcuts/views.py
index 42493f3e7b..85d1922d58 100644
--- a/tests/shortcuts/views.py
+++ b/tests/shortcuts/views.py
@@ -43,6 +43,18 @@ def render_to_response_view_with_dirs(request):
return render_to_response('render_dirs_test.html', dirs=dirs)
+def render_to_response_view_with_status(request):
+ return render_to_response('shortcuts/render_test.html', {
+ 'foo': 'FOO',
+ 'bar': 'BAR',
+ }, status=403)
+
+
+def render_to_response_view_with_using(request):
+ using = request.GET.get('using')
+ return render_to_response('shortcuts/using.html', using=using)
+
+
def context_processor(request):
return {'bar': 'context processor output'}
@@ -95,6 +107,11 @@ def render_view_with_status(request):
}, status=403)
+def render_view_with_using(request):
+ using = request.GET.get('using')
+ return render(request, 'shortcuts/using.html', using=using)
+
+
def render_view_with_current_app(request):
return render(request, 'shortcuts/render_test.html', {
'foo': 'FOO',
diff --git a/tests/template_tests/jinja2/template_tests/using.html b/tests/template_tests/jinja2/template_tests/using.html
new file mode 100644
index 0000000000..8ce973e958
--- /dev/null
+++ b/tests/template_tests/jinja2/template_tests/using.html
@@ -0,0 +1 @@
+Jinja2
diff --git a/tests/template_tests/templates/template_tests/using.html b/tests/template_tests/templates/template_tests/using.html
new file mode 100644
index 0000000000..65bcbf65a4
--- /dev/null
+++ b/tests/template_tests/templates/template_tests/using.html
@@ -0,0 +1 @@
+DTL
diff --git a/tests/template_tests/test_response.py b/tests/template_tests/test_response.py
index 993b2002c8..3807789e63 100644
--- a/tests/template_tests/test_response.py
+++ b/tests/template_tests/test_response.py
@@ -11,6 +11,7 @@ from django.template import Context, engines
from django.template.response import (TemplateResponse, SimpleTemplateResponse,
ContentNotRenderedError)
from django.test import ignore_warnings, override_settings
+from django.test.utils import require_jinja2
from django.utils._os import upath
from django.utils.deprecation import RemovedInDjango20Warning
@@ -133,6 +134,15 @@ class SimpleTemplateResponseTest(SimpleTestCase):
self.assertEqual(response['content-type'], 'application/json')
self.assertEqual(response.status_code, 504)
+ @require_jinja2
+ def test_using(self):
+ response = SimpleTemplateResponse('template_tests/using.html').render()
+ self.assertEqual(response.content, b'DTL\n')
+ response = SimpleTemplateResponse('template_tests/using.html', using='django').render()
+ self.assertEqual(response.content, b'DTL\n')
+ response = SimpleTemplateResponse('template_tests/using.html', using='jinja2').render()
+ self.assertEqual(response.content, b'Jinja2\n')
+
def test_post_callbacks(self):
"Rendering a template response triggers the post-render callbacks"
post = []
@@ -260,6 +270,16 @@ class TemplateResponseTest(SimpleTestCase):
self.assertEqual(response['content-type'], 'application/json')
self.assertEqual(response.status_code, 504)
+ @require_jinja2
+ def test_using(self):
+ request = self.factory.get('/')
+ response = TemplateResponse(request, 'template_tests/using.html').render()
+ self.assertEqual(response.content, b'DTL\n')
+ response = TemplateResponse(request, 'template_tests/using.html', using='django').render()
+ self.assertEqual(response.content, b'DTL\n')
+ response = TemplateResponse(request, 'template_tests/using.html', using='jinja2').render()
+ self.assertEqual(response.content, b'Jinja2\n')
+
@ignore_warnings(category=RemovedInDjango20Warning)
def test_custom_app(self):
self._response('{{ foo }}', current_app="foobar")