Fixed #12816 -- Added a render() shortcut.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@15008 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Russell Keith-Magee 2010-12-21 17:18:41 +00:00
parent d4ef841495
commit b3d2091681
8 changed files with 195 additions and 14 deletions

View File

@ -4,7 +4,7 @@ of MVC. In other words, these functions/classes introduce controlled coupling
for convenience's sake.
"""
from django.template import loader
from django.template import loader, RequestContext
from django.http import HttpResponse, Http404
from django.http import HttpResponseRedirect, HttpResponsePermanentRedirect
from django.db.models.manager import Manager
@ -19,20 +19,31 @@ def render_to_response(*args, **kwargs):
httpresponse_kwargs = {'mimetype': kwargs.pop('mimetype', None)}
return HttpResponse(loader.render_to_string(*args, **kwargs), **httpresponse_kwargs)
def render(request, *args, **kwargs):
"""
Returns a HttpResponse whose content is filled with the result of calling
django.template.loader.render_to_string() with the passed arguments.
Uses a RequestContext by default.
"""
httpresponse_kwargs = {'mimetype': kwargs.pop('mimetype', None)}
kwargs['context_instance'] = kwargs.get('context_instance', RequestContext(request))
return HttpResponse(loader.render_to_string(*args, **kwargs),
**httpresponse_kwargs)
def redirect(to, *args, **kwargs):
"""
Returns an HttpResponseRedirect to the apropriate URL for the arguments
passed.
The arguments could be:
* A model: the model's `get_absolute_url()` function will be called.
* A view name, possibly with arguments: `urlresolvers.reverse()` will
be used to reverse-resolve the name.
* A URL, which will be used as-is for the redirect location.
By default issues a temporary redirect; pass permanent=True to issue a
permanent redirect
"""
@ -40,11 +51,11 @@ def redirect(to, *args, **kwargs):
redirect_class = HttpResponsePermanentRedirect
else:
redirect_class = HttpResponseRedirect
# If it's a model, use get_absolute_url()
if hasattr(to, 'get_absolute_url'):
return redirect_class(to.get_absolute_url())
# Next try a reverse URL resolution.
try:
return redirect_class(urlresolvers.reverse(to, args=args, kwargs=kwargs))
@ -55,7 +66,7 @@ def redirect(to, *args, **kwargs):
# If this doesn't "feel" like a URL, re-raise.
if '/' not in to and '.' not in to:
raise
# Finally, fall back and assume it's a URL
return redirect_class(to)
@ -101,4 +112,5 @@ def get_list_or_404(klass, *args, **kwargs):
obj_list = list(queryset.filter(*args, **kwargs))
if not obj_list:
raise Http404('No %s matches the given query.' % queryset.model._meta.object_name)
return obj_list
return obj_list

View File

@ -215,6 +215,11 @@ requests. These include:
making it easier to write simple template tags that require
access to template context.
* A new :meth:`~django.shortcuts.render()` shortcut -- an
alternative to :meth:`~django.shortcuts.render_to_response()`
providing a :class:`~django.template.RequestContext` by
default.
.. _HTTPOnly: http://www.owasp.org/index.php/HTTPOnly
.. _backwards-incompatible-changes-1.3:

View File

@ -12,6 +12,70 @@ The package ``django.shortcuts`` collects helper functions and classes that
"span" multiple levels of MVC. In other words, these functions/classes
introduce controlled coupling for convenience's sake.
``render``
==========
.. function:: render(request, template[, dictionary][, context_instance][, mimetype])
Combines a given template with a given context dictionary and returns an
:class:`~django.http.HttpResponse` object with that rendered text.
:func:`render()` is the same as a call to
:func:`render_to_response()` with a context_instance argument that
that forces the use of a :class:`RequestContext`.
Required arguments
------------------
``request``
The request object used to generate this response.
``template``
The full name of a template to use or sequence of template names.
Optional arguments
------------------
``dictionary``
A dictionary of values to add to the template context. By default, this
is an empty dictionary. If a value in the dictionary is callable, the
view will call it just before rendering the template.
``context_instance``
The context instance to render the template with. By default, the template
will be rendered with a ``RequestContext`` instance (filled with values from
``request`` and ```dictionary``).
``mimetype``
The MIME type to use for the resulting document. Defaults to the value of
the :setting:`DEFAULT_CONTENT_TYPE` setting.
Example
-------
The following example renders the template ``myapp/index.html`` with the
MIME type ``application/xhtml+xml``::
from django.shortcuts import render_to_response
def my_view(request):
# View code here...
return render_to_response('myapp/index.html', {"foo": "bar"},
mimetype="application/xhtml+xml")
This example is equivalent to::
from django.http import HttpResponse
from django.template import Context, loader
def my_view(request):
# View code here...
t = loader.get_template('myapp/template.html')
c = RequestContext(request, {'foo': 'bar'})
return HttpResponse(t.render(c),
mimetype="application/xhtml+xml")
``render_to_response``
======================

View File

@ -1 +1 @@
{{ foo }}.{{ bar }}.{{ baz }}.{{ processors }}
{{ foo }}.{{ bar }}.{{ baz }}.{{ STATIC_URL }}

View File

@ -5,5 +5,6 @@ from generic.date_based import *
from generic.object_list import *
from generic.simple import *
from i18n import *
from shortcuts import *
from specials import *
from static import *

View File

@ -0,0 +1,53 @@
from django.conf import settings
from django.test import TestCase
class ShortcutTests(TestCase):
def setUp(self):
self.old_STATIC_URL = settings.STATIC_URL
self.old_TEMPLATE_CONTEXT_PROCESSORS = settings.TEMPLATE_CONTEXT_PROCESSORS
settings.STATIC_URL = '/path/to/static/media'
settings.TEMPLATE_CONTEXT_PROCESSORS = (
'django.core.context_processors.static'
)
def tearDown(self):
settings.STATIC_URL = self.old_STATIC_URL
settings.TEMPLATE_CONTEXT_PROCESSORS = self.old_TEMPLATE_CONTEXT_PROCESSORS
def test_render_to_response(self):
response = self.client.get('/views/shortcuts/render_to_response/')
self.assertEquals(response.status_code, 200)
self.assertEquals(response.content, 'FOO.BAR..\n')
self.assertEquals(response['Content-Type'], 'text/html; charset=utf-8')
def test_render_to_response_with_request_context(self):
response = self.client.get('/views/shortcuts/render_to_response/request_context/')
self.assertEquals(response.status_code, 200)
self.assertEquals(response.content, 'FOO.BAR../path/to/static/media\n')
self.assertEquals(response['Content-Type'], 'text/html; charset=utf-8')
def test_render_to_response_with_mimetype(self):
response = self.client.get('/views/shortcuts/render_to_response/mimetype/')
self.assertEquals(response.status_code, 200)
self.assertEquals(response.content, 'FOO.BAR..\n')
self.assertEquals(response['Content-Type'], 'application/x-rendertest')
def test_render(self):
response = self.client.get('/views/shortcuts/render/')
self.assertEquals(response.status_code, 200)
self.assertEquals(response.content, 'FOO.BAR../path/to/static/media\n')
self.assertEquals(response['Content-Type'], 'text/html; charset=utf-8')
def test_render_with_base_context(self):
response = self.client.get('/views/shortcuts/render/base_context/')
self.assertEquals(response.status_code, 200)
self.assertEquals(response.content, 'FOO.BAR..\n')
self.assertEquals(response['Content-Type'], 'text/html; charset=utf-8')
def test_render_with_mimetype(self):
response = self.client.get('/views/shortcuts/render/mimetype/')
self.assertEquals(response.status_code, 200)
self.assertEquals(response.content, 'FOO.BAR../path/to/static/media\n')
self.assertEquals(response['Content-Type'], 'application/x-rendertest')

View File

@ -143,6 +143,14 @@ urlpatterns += patterns('django.views.generic.simple',
urlpatterns += patterns('regressiontests.views.views',
url(r'view_exception/(?P<n>\d+)/$', 'view_exception', name='view_exception'),
url(r'template_exception/(?P<n>\d+)/$', 'template_exception', name='template_exception'),
(r'^shortcuts/render_to_response/$', 'render_to_response_view'),
(r'^shortcuts/render_to_response/request_context/$', 'render_to_response_view_with_request_context'),
(r'^shortcuts/render_to_response/mimetype/$', 'render_to_response_view_with_mimetype'),
(r'^shortcuts/render/$', 'render_view'),
(r'^shortcuts/render/base_context/$', 'render_view_with_base_context'),
(r'^shortcuts/render/mimetype/$', 'render_view_with_mimetype'),
)
# simple generic views.

View File

@ -1,11 +1,12 @@
import sys
from django.http import HttpResponse, HttpResponseRedirect
from django import forms
from django.http import HttpResponse, HttpResponseRedirect
from django.core.urlresolvers import get_resolver
from django.shortcuts import render_to_response, render
from django.template import Context, RequestContext
from django.views.debug import technical_500_response
from django.views.generic.create_update import create_object
from django.core.urlresolvers import get_resolver
from django.shortcuts import render_to_response
from regressiontests.views import BrokenException, except_args
@ -57,3 +58,40 @@ def template_exception(request, n):
return render_to_response('debug/template_exception.html',
{'arg': except_args[int(n)]})
# Some views to exercise the shortcuts
def render_to_response_view(request):
return render_to_response('debug/render_test.html', {
'foo': 'FOO',
'bar': 'BAR',
})
def render_to_response_view_with_request_context(request):
return render_to_response('debug/render_test.html', {
'foo': 'FOO',
'bar': 'BAR',
}, context_instance=RequestContext(request))
def render_to_response_view_with_mimetype(request):
return render_to_response('debug/render_test.html', {
'foo': 'FOO',
'bar': 'BAR',
}, mimetype='application/x-rendertest')
def render_view(request):
return render(request, 'debug/render_test.html', {
'foo': 'FOO',
'bar': 'BAR',
})
def render_view_with_base_context(request):
return render(request, 'debug/render_test.html', {
'foo': 'FOO',
'bar': 'BAR',
}, context_instance=Context())
def render_view_with_mimetype(request):
return render(request, 'debug/render_test.html', {
'foo': 'FOO',
'bar': 'BAR',
}, mimetype='application/x-rendertest')