aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/api-guide/renderers.md2
-rw-r--r--rest_framework/renderers.py35
-rw-r--r--rest_framework/response.py16
-rw-r--r--rest_framework/tests/htmlrenderer.py50
4 files changed, 88 insertions, 15 deletions
diff --git a/docs/api-guide/renderers.md b/docs/api-guide/renderers.md
index e1c83477..ef0ed46f 100644
--- a/docs/api-guide/renderers.md
+++ b/docs/api-guide/renderers.md
@@ -127,7 +127,7 @@ For example:
# and additionally requiresa 'template_name'.
# It does not require serialization.
data = {'users': queryset}
- return Response(data, template='list_users.html')
+ return Response(data, template_name='list_users.html')
# JSONRenderer requires serialized data as normal.
serializer = UserSerializer(instance=queryset)
diff --git a/rest_framework/renderers.py b/rest_framework/renderers.py
index 3227a03a..4157468f 100644
--- a/rest_framework/renderers.py
+++ b/rest_framework/renderers.py
@@ -10,6 +10,7 @@ from django import forms
from django.template import RequestContext, loader
from django.utils import simplejson as json
from rest_framework.compat import yaml
+from rest_framework.exceptions import ConfigurationError
from rest_framework.settings import api_settings
from rest_framework.request import clone_request
from rest_framework.utils import dict2xml
@@ -142,19 +143,41 @@ class HTMLTemplateRenderer(BaseRenderer):
media_type = 'text/html'
format = 'html'
- template = None
+ template_name = None
def render(self, data=None, accepted_media_type=None):
"""
- Renders *obj* using the :attr:`template` specified on the class.
+ Renders data to HTML, using Django's standard template rendering.
+
+ The template name is determined by (in order of preference):
+
+ 1. An explicit .template_name set on the response.
+ 2. An explicit .template_name set on this class.
+ 3. The return result of calling view.get_template_names().
"""
- if data is None:
- return ''
+ view = self.view
+ request, response = view.request, view.response
- template = loader.get_template(self.template)
- context = RequestContext(self.view.request, {'object': data})
+ template_names = self.get_template_names(response, view)
+ template = self.resolve_template(template_names)
+ context = self.resolve_context(data, request)
return template.render(context)
+ def resolve_template(self, template_names):
+ return loader.select_template(template_names)
+
+ def resolve_context(self, data, request):
+ return RequestContext(request, data)
+
+ def get_template_names(self, response, view):
+ if response.template_name:
+ return [response.template_name]
+ elif self.template_name:
+ return [self.template_name]
+ elif hasattr(view, 'get_template_names'):
+ return view.get_template_names()
+ raise ConfigurationError('Returned a template response with no template_name')
+
class DocumentingHTMLRenderer(BaseRenderer):
"""
diff --git a/rest_framework/response.py b/rest_framework/response.py
index fca631c3..796750fc 100644
--- a/rest_framework/response.py
+++ b/rest_framework/response.py
@@ -8,8 +8,8 @@ class Response(SimpleTemplateResponse):
arbitrary media types.
"""
- def __init__(self, data=None, status=None, headers=None,
- renderer=None, accepted_media_type=None):
+ def __init__(self, data=None, status=None,
+ template_name=None, headers=None):
"""
Alters the init arguments slightly.
For example, drop 'template_name', and instead use 'data'.
@@ -20,21 +20,21 @@ class Response(SimpleTemplateResponse):
super(Response, self).__init__(None, status=status)
self.data = data
self.headers = headers and headers[:] or []
-
- self.accepted_renderer = renderer
- self.accepted_media_type = accepted_media_type
+ self.template_name = template_name
@property
def rendered_content(self):
renderer = self.accepted_renderer
+ media_type = self.accepted_media_type
- assert renderer, "No renderer set on Response"
+ assert renderer, "No accepted renderer set on Response"
+ assert media_type, "No accepted media type set on Response"
- self['content-type'] = self.accepted_media_type
+ self['content-type'] = media_type
if self.data is None:
return renderer.render()
- return renderer.render(self.data, self.accepted_media_type)
+ return renderer.render(self.data, media_type)
@property
def status_text(self):
diff --git a/rest_framework/tests/htmlrenderer.py b/rest_framework/tests/htmlrenderer.py
new file mode 100644
index 00000000..2c672dd0
--- /dev/null
+++ b/rest_framework/tests/htmlrenderer.py
@@ -0,0 +1,50 @@
+from django.conf.urls.defaults import patterns, url
+from django.test import TestCase
+from django.template import TemplateDoesNotExist, Template
+import django.template.loader
+from rest_framework.decorators import api_view, renderer_classes
+from rest_framework.renderers import HTMLTemplateRenderer
+from rest_framework.response import Response
+
+
+@api_view(('GET',))
+@renderer_classes((HTMLTemplateRenderer,))
+def example(request):
+ """
+ A view that can returns an HTML representation.
+ """
+ data = {'object': 'foobar'}
+ return Response(data, template_name='example.html')
+
+
+urlpatterns = patterns('',
+ url(r'^$', example),
+)
+
+
+class HTMLRendererTests(TestCase):
+ urls = 'rest_framework.tests.htmlrenderer'
+
+ def setUp(self):
+ """
+ Monkeypatch get_template
+ """
+ self.get_template = django.template.loader.get_template
+
+ def get_template(template_name):
+ if template_name == 'example.html':
+ return Template("example: {{ object }}")
+ raise TemplateDoesNotExist(template_name)
+
+ django.template.loader.get_template = get_template
+
+ def tearDown(self):
+ """
+ Revert monkeypatching
+ """
+ django.template.loader.get_template = self.get_template
+
+ def test_simple_html_view(self):
+ response = self.client.get('/')
+ self.assertContains(response, "example: foobar")
+ self.assertEquals(response['content-type'], 'text/html')