django-rest-framework/api-guide/renderers.html

281 lines
20 KiB
HTML
Raw Normal View History

2012-09-02 00:24:33 +04:00
<!DOCTYPE html>
<html lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<title>Django REST framework</title>
2012-10-05 18:26:53 +04:00
<link href="http://tomchristie.github.com/django-rest-framework/img/favicon.ico" rel="icon" type="image/x-icon">
2012-09-02 00:24:33 +04:00
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="">
<meta name="author" content="">
<!-- Le styles -->
2012-09-08 23:24:07 +04:00
<link href="http://tomchristie.github.com/django-rest-framework/css/prettify.css" rel="stylesheet">
2012-09-02 00:37:41 +04:00
<link href="http://tomchristie.github.com/django-rest-framework/css/bootstrap.css" rel="stylesheet">
<link href="http://tomchristie.github.com/django-rest-framework/css/bootstrap-responsive.css" rel="stylesheet">
2012-09-13 12:40:09 +04:00
<link href="http://tomchristie.github.com/django-rest-framework/css/default.css" rel="stylesheet">
2012-09-02 00:24:33 +04:00
<!-- Le HTML5 shim, for IE6-8 support of HTML5 elements -->
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
2012-10-01 19:27:59 +04:00
<body onload="prettyPrint()" class="renderers-page">
2012-09-02 00:24:33 +04:00
2012-10-05 22:27:27 +04:00
<div class="wrapper">
2012-09-02 00:24:33 +04:00
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="navbar-inner">
<div class="container-fluid">
2012-09-12 16:12:00 +04:00
<a class="repo-link btn btn-primary btn-small" href="https://github.com/tomchristie/django-rest-framework/tree/restframework2">GitHub</a>
2012-09-02 00:24:33 +04:00
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
2012-09-02 00:37:41 +04:00
<a class="brand" href="http://tomchristie.github.com/django-rest-framework">Django REST framework</a>
2012-09-02 00:24:33 +04:00
<div class="nav-collapse collapse">
<ul class="nav">
2012-09-02 00:37:41 +04:00
<li><a href="http://tomchristie.github.com/django-rest-framework">Home</a></li>
2012-09-02 00:24:33 +04:00
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Tutorial <b class="caret"></b></a>
<ul class="dropdown-menu">
2012-10-09 15:01:56 +04:00
<li><a href="http://tomchristie.github.com/django-rest-framework/tutorial/quickstart">Quickstart</a></li>
2012-09-02 00:37:41 +04:00
<li><a href="http://tomchristie.github.com/django-rest-framework/tutorial/1-serialization">1 - Serialization</a></li>
<li><a href="http://tomchristie.github.com/django-rest-framework/tutorial/2-requests-and-responses">2 - Requests and responses</a></li>
<li><a href="http://tomchristie.github.com/django-rest-framework/tutorial/3-class-based-views">3 - Class based views</a></li>
<li><a href="http://tomchristie.github.com/django-rest-framework/tutorial/4-authentication-permissions-and-throttling">4 - Authentication, permissions and throttling</a></li>
<li><a href="http://tomchristie.github.com/django-rest-framework/tutorial/5-relationships-and-hyperlinked-apis">5 - Relationships and hyperlinked APIs</a></li>
<li><a href="http://tomchristie.github.com/django-rest-framework/tutorial/6-resource-orientated-projects">6 - Resource orientated projects</a></li>
2012-09-02 00:24:33 +04:00
</ul>
</li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">API Guide <b class="caret"></b></a>
<ul class="dropdown-menu">
2012-09-02 00:37:41 +04:00
<li><a href="http://tomchristie.github.com/django-rest-framework/api-guide/requests">Requests</a></li>
<li><a href="http://tomchristie.github.com/django-rest-framework/api-guide/responses">Responses</a></li>
<li><a href="http://tomchristie.github.com/django-rest-framework/api-guide/views">Views</a></li>
2012-09-12 13:14:01 +04:00
<li><a href="http://tomchristie.github.com/django-rest-framework/api-guide/generic-views">Generic views</a></li>
2012-09-02 00:37:41 +04:00
<li><a href="http://tomchristie.github.com/django-rest-framework/api-guide/parsers">Parsers</a></li>
<li><a href="http://tomchristie.github.com/django-rest-framework/api-guide/renderers">Renderers</a></li>
<li><a href="http://tomchristie.github.com/django-rest-framework/api-guide/serializers">Serializers</a></li>
2012-10-05 20:10:33 +04:00
<li><a href="http://tomchristie.github.com/django-rest-framework/api-guide/fields">Serializer fields</a></li>
2012-09-02 00:37:41 +04:00
<li><a href="http://tomchristie.github.com/django-rest-framework/api-guide/authentication">Authentication</a></li>
<li><a href="http://tomchristie.github.com/django-rest-framework/api-guide/permissions">Permissions</a></li>
<li><a href="http://tomchristie.github.com/django-rest-framework/api-guide/throttling">Throttling</a></li>
2012-10-01 19:27:59 +04:00
<li><a href="http://tomchristie.github.com/django-rest-framework/api-guide/pagination">Pagination</a></li>
2012-09-12 13:14:01 +04:00
<li><a href="http://tomchristie.github.com/django-rest-framework/api-guide/content-negotiation">Content negotiation</a></li>
<li><a href="http://tomchristie.github.com/django-rest-framework/api-guide/format-suffixes">Format suffixes</a></li>
<li><a href="http://tomchristie.github.com/django-rest-framework/api-guide/reverse">Returning URLs</a></li>
2012-09-02 00:37:41 +04:00
<li><a href="http://tomchristie.github.com/django-rest-framework/api-guide/exceptions">Exceptions</a></li>
<li><a href="http://tomchristie.github.com/django-rest-framework/api-guide/status-codes">Status codes</a></li>
2012-09-05 16:05:36 +04:00
<li><a href="http://tomchristie.github.com/django-rest-framework/api-guide/settings">Settings</a></li>
2012-09-02 00:24:33 +04:00
</ul>
</li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Topics <b class="caret"></b></a>
<ul class="dropdown-menu">
2012-09-02 00:37:41 +04:00
<li><a href="http://tomchristie.github.com/django-rest-framework/topics/csrf">Working with AJAX and CSRF</a></li>
2012-10-08 17:26:56 +04:00
<li><a href="http://tomchristie.github.com/django-rest-framework/topics/browserhacks">Browser hacks</a></li>
2012-10-08 15:19:26 +04:00
<li><a href="http://tomchristie.github.com/django-rest-framework/topics/browsable-api">Working with the Browsable API</a></li>
<li><a href="http://tomchristie.github.com/django-rest-framework/topics/rest-hypermedia-hateoas">REST, Hypermedia & HATEOAS</a></li>
2012-09-05 16:05:36 +04:00
<li><a href="http://tomchristie.github.com/django-rest-framework/topics/contributing">Contributing to REST framework</a></li>
2012-10-08 15:19:26 +04:00
<li><a href="http://tomchristie.github.com/django-rest-framework/topics/migration">2.0 Migration Guide</a></li>
<li><a href="http://tomchristie.github.com/django-rest-framework/topics/changelog">Change Log</a></li>
2012-09-02 00:37:41 +04:00
<li><a href="http://tomchristie.github.com/django-rest-framework/topics/credits">Credits</a></li>
2012-09-02 00:24:33 +04:00
</ul>
</li>
</ul>
<ul class="nav pull-right">
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Version: 2.0.0 <b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a href="#">Trunk</a></li>
<li><a href="#">2.0.0</a></li>
</ul>
</li>
</ul>
2012-09-02 00:24:33 +04:00
</div><!--/.nav-collapse -->
</div>
</div>
</div>
2012-10-05 22:27:27 +04:00
<div class="body-content">
<div class="container-fluid">
<div class="row-fluid">
2012-10-05 16:22:18 +04:00
2012-10-05 22:27:27 +04:00
<div class="span3">
2012-10-08 15:19:26 +04:00
<!-- TODO
<p style="margin-top: -12px">
<a class="btn btn-mini btn-primary" style="width: 60px">&laquo; previous</a>
<a class="btn btn-mini btn-primary" style="float: right; margin-right: 8px; width: 60px;">next &raquo;</a>
</p>
-->
2012-10-05 22:27:27 +04:00
<div id="table-of-contents">
<ul class="nav nav-list side-nav well sidebar-nav-fixed">
<li class="main"><a href="#renderers">Renderers</a></li>
2012-10-02 13:41:26 +04:00
<li><a href="#how-the-renderer-is-determined">How the renderer is determined</a></li>
<li><a href="#setting-the-renderers">Setting the renderers</a></li>
<li><a href="#ordering-of-renderer-classes">Ordering of renderer classes</a></li>
2012-10-05 16:22:18 +04:00
<li class="main"><a href="#api-reference">API Reference</a></li>
2012-09-27 19:28:13 +04:00
<li><a href="#jsonrenderer">JSONRenderer</a></li>
<li><a href="#jsonprenderer">JSONPRenderer</a></li>
<li><a href="#yamlrenderer">YAMLRenderer</a></li>
<li><a href="#xmlrenderer">XMLRenderer</a></li>
<li><a href="#documentinghtmlrenderer">DocumentingHTMLRenderer</a></li>
2012-10-05 16:22:18 +04:00
<li><a href="#htmltemplaterenderer">HTMLTemplateRenderer</a></li>
2012-09-27 19:28:13 +04:00
<li><a href="#custom-renderers">Custom renderers</a></li>
2012-10-05 16:22:18 +04:00
<li class="main"><a href="#advanced-renderer-usage">Advanced renderer usage</a></li>
2012-10-05 18:26:53 +04:00
<li><a href="#varying-behaviour-by-media-type">Varying behaviour by media type</a></li>
2012-10-02 13:41:26 +04:00
<li><a href="#designing-your-media-types">Designing your media types</a></li>
2012-09-02 00:24:33 +04:00
2012-10-05 22:27:27 +04:00
</ul>
</div>
</div>
2012-09-02 00:24:33 +04:00
2012-10-05 22:27:27 +04:00
<div id="main-content" class="span9">
<p><a class="github" href="https://github.com/tomchristie/django-rest-framework/blob/restframework2/rest_framework/renderers.py"><span class="label label-info">renderers.py</span></a></p>
2012-09-09 01:06:49 +04:00
<h1 id="renderers">Renderers</h1>
2012-09-27 19:28:13 +04:00
<blockquote>
<p>Before a TemplateResponse instance can be returned to the client, it must be rendered. The rendering process takes the intermediate representation of template and context, and turns it into the final byte stream that can be served to the client.</p>
<p>&mdash; <a href="https://docs.djangoproject.com/en/dev/ref/template-response/#the-rendering-process">Django documentation</a></p>
</blockquote>
2012-10-02 13:41:26 +04:00
<p>REST framework includes a number of built in Renderer classes, that allow you to return responses with various media types. There is also support for defining your own custom renderers, which gives you the flexiblity to design your own media types.</p>
<h2 id="how-the-renderer-is-determined">How the renderer is determined</h2>
<p>The set of valid renderers for a view is always defined as a list of classes. When a view is entered REST framework will perform content negotiation on the incoming request, and determine the most appropriate renderer to satisfy the request.</p>
<p>The basic process of content negotiation involves examining the request's <code>Accept</code> header, to determine which media types it expects in the response. Optionally, format suffixes on the URL may be used to explicitly request a particular representation. For example the URL <code>http://example.com/api/users_count.json</code> might be an endpoint that always returns JSON data.</p>
<p>For more information see the documentation on <a href="content-negotiation">content negotation</a>.</p>
<h2 id="setting-the-renderers">Setting the renderers</h2>
<p>The default set of renderers may be set globally, using the <code>DEFAULT_RENDERERS</code> setting. For example, the following settings would use <code>YAML</code> as the main media type and also include the self describing API.</p>
<pre class="prettyprint lang-py"><code>REST_FRAMEWORK = {
'DEFAULT_RENDERERS': (
'rest_framework.renderers.YAMLRenderer',
'rest_framework.renderers.DocumentingHTMLRenderer',
)
}
</code></pre>
<p>You can also set the renderers used for an individual view, using the <code>APIView</code> class based views.</p>
<pre class="prettyprint lang-py"><code>class UserCountView(APIView):
"""
A view that returns the count of active users, in JSON or JSONp.
"""
renderer_classes = (JSONRenderer, JSONPRenderer)
def get(self, request, format=None):
user_count = User.objects.filter(active=True).count()
content = {'user_count': user_count}
return Response(content)
</code></pre>
<p>Or, if you're using the <code>@api_view</code> decorator with function based views.</p>
<pre class="prettyprint lang-py"><code>@api_view('GET'),
@renderer_classes(JSONRenderer, JSONPRenderer)
def user_count_view(request, format=None):
"""
A view that returns the count of active users, in JSON or JSONp.
"""
user_count = User.objects.filter(active=True).count()
content = {'user_count': user_count}
return Response(content)
</code></pre>
<h2 id="ordering-of-renderer-classes">Ordering of renderer classes</h2>
<p>It's important when specifying the renderer classes for your API to think about what priority you want to assign to each media type. If a client underspecifies the representations it can accept, such as sending an <code>Accept: */*</code> header, or not including an <code>Accept</code> header at all, then REST framework will select the first renderer in the list to use for the response.</p>
<p>For example if your API serves JSON responses and the HTML browseable API, you might want to make <code>JSONRenderer</code> your default renderer, in order to send <code>JSON</code> responses to clients that do not specify an <code>Accept</code> header.</p>
<p>If your API includes views that can serve both regular webpages and API responses depending on the request, then you might consider making <code>TemplateHTMLRenderer</code> your default renderer, in order to play nicely with older browsers that send <a href="http://www.gethifi.com/blog/browser-rest-http-accept-headers">broken accept headers</a>.</p>
2012-10-05 18:26:53 +04:00
<hr />
2012-10-05 16:22:18 +04:00
<h1 id="api-reference">API Reference</h1>
2012-09-27 19:28:13 +04:00
<h2 id="jsonrenderer">JSONRenderer</h2>
2012-10-02 13:41:26 +04:00
<p><strong>.media_type:</strong> <code>application/json</code></p>
<p><strong>.format:</strong> <code>'.json'</code></p>
2012-09-27 19:28:13 +04:00
<h2 id="jsonprenderer">JSONPRenderer</h2>
2012-10-02 13:41:26 +04:00
<p><strong>.media_type:</strong> <code>application/javascript</code></p>
<p><strong>.format:</strong> <code>'.jsonp'</code></p>
2012-09-27 19:28:13 +04:00
<h2 id="yamlrenderer">YAMLRenderer</h2>
2012-10-02 13:41:26 +04:00
<p><strong>.media_type:</strong> <code>application/yaml</code></p>
<p><strong>.format:</strong> <code>'.yaml'</code></p>
2012-09-27 19:28:13 +04:00
<h2 id="xmlrenderer">XMLRenderer</h2>
2012-10-02 13:41:26 +04:00
<p><strong>.media_type:</strong> <code>application/xml</code></p>
<p><strong>.format:</strong> <code>'.xml'</code></p>
2012-09-27 19:28:13 +04:00
<h2 id="documentinghtmlrenderer">DocumentingHTMLRenderer</h2>
2012-10-05 16:22:18 +04:00
<p>Renders data into HTML for the browseable API. This renderer will determine which other renderer would have been given highest priority, and use that to display an API style response within the HTML page.</p>
2012-10-02 13:41:26 +04:00
<p><strong>.media_type:</strong> <code>text/html</code></p>
<p><strong>.format:</strong> <code>'.api'</code></p>
2012-10-05 16:22:18 +04:00
<h2 id="htmltemplaterenderer">HTMLTemplateRenderer</h2>
<p>Renders data to HTML, using Django's standard template rendering.
Unlike other renderers, the data passed to the <code>Response</code> does not need to be serialized. Also, unlike other renderers, you may want to include a <code>template_name</code> argument when creating the <code>Response</code>.</p>
<p>The HTMLTemplateRenderer will create a <code>RequestContext</code>, using the <code>response.data</code> as the context dict, and determine a template name to use to render the context.</p>
<p>The template name is determined by (in order of preference):</p>
<ol>
<li>An explicit <code>.template_name</code> attribute set on the response.</li>
<li>An explicit <code>.template_name</code> attribute set on this class.</li>
<li>The return result of calling <code>view.get_template_names()</code>.</li>
</ol>
<p>You can use <code>HTMLTemplateRenderer</code> either to return regular HTML pages using REST framework, or to return both HTML and API responses from a single endpoint.</p>
<p>If you're building websites that use <code>HTMLTemplateRenderer</code> along with other renderer classes, you should consider listing <code>HTMLTemplateRenderer</code> as the first class in the <code>renderer_classes</code> list, so that it will be prioritised first even for browsers that send poorly formed ACCEPT headers.</p>
2012-10-02 13:41:26 +04:00
<p><strong>.media_type:</strong> <code>text/html</code></p>
<p><strong>.format:</strong> <code>'.html'</code></p>
2012-09-27 19:28:13 +04:00
<h2 id="custom-renderers">Custom renderers</h2>
2012-10-02 13:41:26 +04:00
<p>To implement a custom renderer, you should override <code>BaseRenderer</code>, set the <code>.media_type</code> and <code>.format</code> properties, and implement the <code>.render(self, data, media_type)</code> method.</p>
2012-10-05 18:26:53 +04:00
<hr />
2012-10-05 16:22:18 +04:00
<h1 id="advanced-renderer-usage">Advanced renderer usage</h1>
2012-10-02 13:41:26 +04:00
<p>You can do some pretty flexible things using REST framework's renderers. Some examples...</p>
<ul>
<li>Provide either flat or nested representations from the same endpoint, depending on the requested media type.</li>
<li>Serve both regular HTML webpages, and JSON based API responses from the same endpoints.</li>
<li>Specify multiple types of HTML representation for API clients to use.</li>
<li>Underspecify a renderer's media type, such as using <code>media_type = 'image/*'</code>, and use the <code>Accept</code> header to vary the encoding of the response. </li>
</ul>
2012-10-05 18:26:53 +04:00
<h2 id="varying-behaviour-by-media-type">Varying behaviour by media type</h2>
2012-10-02 13:41:26 +04:00
<p>In some cases you might want your view to use different serialization styles depending on the accepted media type. If you need to do this you can access <code>request.accepted_renderer</code> to determine the negotiated renderer that will be used for the response.</p>
<p>For example:</p>
<pre class="prettyprint lang-py"><code>@api_view(('GET',))
@renderer_classes((TemplateHTMLRenderer, JSONRenderer))
def list_users(request):
"""
A view that can return JSON or HTML representations
of the users in the system.
"""
queryset = Users.objects.filter(active=True)
2012-10-05 16:22:18 +04:00
if request.accepted_media_type == 'text/html':
2012-10-02 13:41:26 +04:00
# TemplateHTMLRenderer takes a context dict,
2012-10-05 16:22:18 +04:00
# and additionally requiresa 'template_name'.
# It does not require serialization.
2012-10-02 13:41:26 +04:00
data = {'users': queryset}
2012-10-05 16:22:18 +04:00
return Response(data, template_name='list_users.html')
2012-10-02 13:41:26 +04:00
2012-10-05 16:22:18 +04:00
# JSONRenderer requires serialized data as normal.
serializer = UserSerializer(instance=queryset)
data = serializer.data
2012-10-02 13:41:26 +04:00
return Response(data)
</code></pre>
<h2 id="designing-your-media-types">Designing your media types</h2>
<p>For the purposes of many Web APIs, simple <code>JSON</code> responses with hyperlinked relations may be sufficient. If you want to fully embrace RESTful design and <a href="http://timelessrepo.com/haters-gonna-hateoas">HATEOAS</a> you'll neeed to consider the design and usage of your media types in more detail.</p>
<p>In <a href="http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven">the words of Roy Fielding</a>, "A REST API should spend almost all of its descriptive effort in defining the media type(s) used for representing resources and driving application state, or in defining extended relation names and/or hypertext-enabled mark-up for existing standard media types.".</p>
<p>For good examples of custom media types, see GitHub's use of a custom <a href="http://developer.github.com/v3/media/">application/vnd.github+json</a> media type, and Mike Amundsen's IANA approved <a href="http://www.amundsen.com/media-types/collection/">application/vnd.collection+json</a> JSON-based hypermedia.</p>
2012-10-05 22:27:27 +04:00
</div><!--/span-->
</div><!--/row-->
</div><!--/.fluid-container-->
</div><!--/.body content-->
2012-09-02 00:24:33 +04:00
2012-10-05 18:26:53 +04:00
<div id="push"></div>
2012-10-05 22:27:27 +04:00
</div><!--/.wrapper -->
2012-10-05 18:26:53 +04:00
2012-10-05 22:27:27 +04:00
<footer class="span12">
2012-10-05 22:33:52 +04:00
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a></p>
2012-10-05 22:27:27 +04:00
</footer>
2012-10-05 18:26:53 +04:00
2012-09-02 00:24:33 +04:00
<!-- Le javascript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="http://tomchristie.github.com/django-rest-framework/js/jquery-1.8.1-min.js"></script>
2012-10-05 16:22:18 +04:00
<script src="http://tomchristie.github.com/django-rest-framework/js/prettify-1.0.js"></script>
<script src="http://tomchristie.github.com/django-rest-framework/js/bootstrap-2.1.1-min.js"></script>
2012-09-02 00:24:33 +04:00
<script>
//$('.side-nav').scrollspy()
var shiftWindow = function() { scrollBy(0, -50) };
if (location.hash) shiftWindow();
window.addEventListener("hashchange", shiftWindow);
2012-09-12 13:14:01 +04:00
2012-09-17 23:21:26 +04:00
$('.dropdown-menu').on('click touchstart', function(event) {
2012-09-12 13:14:01 +04:00
event.stopPropagation();
});
2012-09-02 00:24:33 +04:00
</script>
2012-10-01 19:27:59 +04:00
</body></html>