mirror of
https://github.com/encode/django-rest-framework.git
synced 2026-01-15 04:48:47 +03:00
gh-pages hosted docs
This commit is contained in:
commit
d5edf20cee
533
api-guide/authentication.html
Normal file
533
api-guide/authentication.html
Normal file
|
|
@ -0,0 +1,533 @@
|
|||
<!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 - Authentication</title>
|
||||
<link href="http://django-rest-framework.org/img/favicon.ico" rel="icon" type="image/x-icon">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Django, API, REST, Authentication, API Reference, Custom authentication, Third party packages">
|
||||
<meta name="author" content="Tom Christie">
|
||||
|
||||
<!-- Le styles -->
|
||||
<link href="http://django-rest-framework.org/css/prettify.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/bootstrap.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/bootstrap-responsive.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/default.css" rel="stylesheet">
|
||||
|
||||
<!-- 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]-->
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-18852272-2']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="prettyPrint()" class="authentication-page">
|
||||
|
||||
<div class="wrapper">
|
||||
|
||||
<div class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container-fluid">
|
||||
<a class="repo-link btn btn-primary btn-small" href="https://github.com/tomchristie/django-rest-framework/tree/master">GitHub</a>
|
||||
<a class="repo-link btn btn-inverse btn-small " href="../api-guide/permissions.html">Next <i class="icon-arrow-right icon-white"></i></a>
|
||||
<a class="repo-link btn btn-inverse btn-small " href="../api-guide/relations.html"><i class="icon-arrow-left icon-white"></i> Previous</a>
|
||||
<a class="repo-link btn btn-inverse btn-small" href="#searchModal" data-toggle="modal"><i class="icon-search icon-white"></i> Search</a>
|
||||
<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>
|
||||
<a class="brand" href="http://django-rest-framework.org">Django REST framework</a>
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav">
|
||||
<li><a href="http://django-rest-framework.org">Home</a></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Tutorial <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/tutorial/quickstart.html">Quickstart</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/1-serialization.html">1 - Serialization</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/2-requests-and-responses.html">2 - Requests and responses</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/3-class-based-views.html">3 - Class based views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/4-authentication-and-permissions.html">4 - Authentication and permissions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/5-relationships-and-hyperlinked-apis.html">5 - Relationships and hyperlinked APIs</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/6-viewsets-and-routers.html">6 - Viewsets and routers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">API Guide <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/api-guide/requests.html">Requests</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/responses.html">Responses</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/views.html">Views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/generic-views.html">Generic views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/viewsets.html">Viewsets</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/routers.html">Routers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/parsers.html">Parsers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/renderers.html">Renderers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/serializers.html">Serializers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/fields.html">Serializer fields</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/relations.html">Serializer relations</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/authentication.html">Authentication</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/permissions.html">Permissions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/throttling.html">Throttling</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/filtering.html">Filtering</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/pagination.html">Pagination</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/content-negotiation.html">Content negotiation</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/format-suffixes.html">Format suffixes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/reverse.html">Returning URLs</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/exceptions.html">Exceptions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/status-codes.html">Status codes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/testing.html">Testing</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/settings.html">Settings</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Topics <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/topics/documenting-your-api.html">Documenting your API</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/ajax-csrf-cors.html">AJAX, CSRF & CORS</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/browser-enhancements.html">Browser enhancements</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/browsable-api.html">The Browsable API</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/rest-hypermedia-hateoas.html">REST, Hypermedia & HATEOAS</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/rest-framework-2-announcement.html">2.0 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/2.2-announcement.html">2.2 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/2.3-announcement.html">2.3 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/release-notes.html">Release Notes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/credits.html">Credits</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="nav pull-right">
|
||||
<!-- TODO
|
||||
<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>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="body-content">
|
||||
<div class="container-fluid">
|
||||
|
||||
<!-- Search Modal -->
|
||||
<div id="searchModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3 id="myModalLabel">Documentation search</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<!-- Custom google search -->
|
||||
<script>
|
||||
(function() {
|
||||
var cx = '015016005043623903336:rxraeohqk6w';
|
||||
var gcse = document.createElement('script');
|
||||
gcse.type = 'text/javascript';
|
||||
gcse.async = true;
|
||||
gcse.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') +
|
||||
'//www.google.com/cse/cse.js?cx=' + cx;
|
||||
var s = document.getElementsByTagName('script')[0];
|
||||
s.parentNode.insertBefore(gcse, s);
|
||||
})();
|
||||
</script>
|
||||
<gcse:search></gcse:search>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row-fluid">
|
||||
|
||||
<div class="span3">
|
||||
<!-- TODO
|
||||
<p style="margin-top: -12px">
|
||||
<a class="btn btn-mini btn-primary" style="width: 60px">« previous</a>
|
||||
<a class="btn btn-mini btn-primary" style="float: right; margin-right: 8px; width: 60px;">next »</a>
|
||||
</p>
|
||||
-->
|
||||
<div id="table-of-contents">
|
||||
<ul class="nav nav-list side-nav well sidebar-nav-fixed">
|
||||
<li class="main"><a href="#authentication">Authentication</a></li>
|
||||
<li><a href="#how-authentication-is-determined">How authentication is determined</a></li>
|
||||
<li><a href="#setting-the-authentication-scheme">Setting the authentication scheme</a></li>
|
||||
<li><a href="#unauthorized-and-forbidden-responses">Unauthorized and Forbidden responses</a></li>
|
||||
<li><a href="#apache-mod_wsgi-specific-configuration">Apache mod_wsgi specific configuration</a></li>
|
||||
<li class="main"><a href="#api-reference">API Reference</a></li>
|
||||
<li><a href="#basicauthentication">BasicAuthentication</a></li>
|
||||
<li><a href="#tokenauthentication">TokenAuthentication</a></li>
|
||||
<li><a href="#sessionauthentication">SessionAuthentication</a></li>
|
||||
<li><a href="#oauthauthentication">OAuthAuthentication</a></li>
|
||||
<li><a href="#oauth2authentication">OAuth2Authentication</a></li>
|
||||
<li class="main"><a href="#custom-authentication">Custom authentication</a></li>
|
||||
<li><a href="#example">Example</a></li>
|
||||
<li class="main"><a href="#third-party-packages">Third party packages</a></li>
|
||||
<li><a href="#digest-authentication">Digest Authentication</a></li>
|
||||
<li><a href="#django-oauth-toolkit">Django OAuth Toolkit</a></li>
|
||||
<li><a href="#django-oauth2-consumer">Django OAuth2 Consumer</a></li>
|
||||
|
||||
<div>
|
||||
<hr>
|
||||
|
||||
<p><strong>The team behind REST framework are launching a new API service.</strong></p>
|
||||
|
||||
<p>If you want to be first in line when we start issuing invitations, please sign up here:</p>
|
||||
|
||||
<!-- Begin MailChimp Signup Form -->
|
||||
<link href="//cdn-images.mailchimp.com/embedcode/slim-081711.css" rel="stylesheet" type="text/css">
|
||||
<style type="text/css">
|
||||
#mc_embed_signup{background:#fff; clear:left; font:14px Helvetica,Arial,sans-serif; }
|
||||
/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
|
||||
We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
|
||||
</style>
|
||||
<div id="mc_embed_signup" style="background: rgb(245, 245, 245)">
|
||||
<form action="http://dabapps.us1.list-manage1.com/subscribe/post?u=cf73a9994eb5b8d8d461b5dfb&id=cb6af8e8bd" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>
|
||||
<!-- <label for="mce-EMAIL">Keep me posted!</label>
|
||||
--> <input style="width: 90%" type="email" value="" name="EMAIL" class="email" id="mce-EMAIL" placeholder="email address" required>
|
||||
<div class="clear"><input class="btn btn-success" type="submit" value="Yes, keep me posted!" name="subscribe" id="mc-embedded-subscribe" class="button"></div>
|
||||
</form>
|
||||
</div>
|
||||
</style></div>
|
||||
</ul>
|
||||
|
||||
|
||||
<!--End mc_embed_signup-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="main-content" class="span9">
|
||||
<p><a class="github" href="https://github.com/tomchristie/django-rest-framework/tree/master/rest_framework/authentication.py"><span class="label label-info">authentication.py</span></a></p>
|
||||
<h1 id="authentication">Authentication</h1>
|
||||
<blockquote>
|
||||
<p>Auth needs to be pluggable.</p>
|
||||
<p>— Jacob Kaplan-Moss, <a href="http://jacobian.org/writing/rest-worst-practices/">"REST worst practices"</a></p>
|
||||
</blockquote>
|
||||
<p>Authentication is the mechanism of associating an incoming request with a set of identifying credentials, such as the user the request came from, or the token that it was signed with. The <a href="permissions.html">permission</a> and <a href="throttling.html">throttling</a> policies can then use those credentials to determine if the request should be permitted.</p>
|
||||
<p>REST framework provides a number of authentication schemes out of the box, and also allows you to implement custom schemes.</p>
|
||||
<p>Authentication is always run at the very start of the view, before the permission and throttling checks occur, and before any other code is allowed to proceed.</p>
|
||||
<p>The <code>request.user</code> property will typically be set to an instance of the <code>contrib.auth</code> package's <code>User</code> class.</p>
|
||||
<p>The <code>request.auth</code> property is used for any additional authentication information, for example, it may be used to represent an authentication token that the request was signed with.</p>
|
||||
<hr />
|
||||
<p><strong>Note:</strong> Don't forget that <strong>authentication by itself won't allow or disallow an incoming request</strong>, it simply identifies the credentials that the request was made with.</p>
|
||||
<p>For information on how to setup the permission polices for your API please see the <a href="permissions.html">permissions documentation</a>.</p>
|
||||
<hr />
|
||||
<h2 id="how-authentication-is-determined">How authentication is determined</h2>
|
||||
<p>The authentication schemes are always defined as a list of classes. REST framework will attempt to authenticate with each class in the list, and will set <code>request.user</code> and <code>request.auth</code> using the return value of the first class that successfully authenticates.</p>
|
||||
<p>If no class authenticates, <code>request.user</code> will be set to an instance of <code>django.contrib.auth.models.AnonymousUser</code>, and <code>request.auth</code> will be set to <code>None</code>.</p>
|
||||
<p>The value of <code>request.user</code> and <code>request.auth</code> for unauthenticated requests can be modified using the <code>UNAUTHENTICATED_USER</code> and <code>UNAUTHENTICATED_TOKEN</code> settings.</p>
|
||||
<h2 id="setting-the-authentication-scheme">Setting the authentication scheme</h2>
|
||||
<p>The default authentication schemes may be set globally, using the <code>DEFAULT_AUTHENTICATION</code> setting. For example.</p>
|
||||
<pre class="prettyprint lang-py"><code>REST_FRAMEWORK = {
|
||||
'DEFAULT_AUTHENTICATION_CLASSES': (
|
||||
'rest_framework.authentication.BasicAuthentication',
|
||||
'rest_framework.authentication.SessionAuthentication',
|
||||
)
|
||||
}
|
||||
</code></pre>
|
||||
<p>You can also set the authentication scheme on a per-view or per-viewset basis,
|
||||
using the <code>APIView</code> class based views.</p>
|
||||
<pre class="prettyprint lang-py"><code>from rest_framework.authentication import SessionAuthentication, BasicAuthentication
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
|
||||
class ExampleView(APIView):
|
||||
authentication_classes = (SessionAuthentication, BasicAuthentication)
|
||||
permission_classes = (IsAuthenticated,)
|
||||
|
||||
def get(self, request, format=None):
|
||||
content = {
|
||||
'user': unicode(request.user), # `django.contrib.auth.User` instance.
|
||||
'auth': unicode(request.auth), # None
|
||||
}
|
||||
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'])
|
||||
@authentication_classes((SessionAuthentication, BasicAuthentication))
|
||||
@permission_classes((IsAuthenticated,))
|
||||
def example_view(request, format=None):
|
||||
content = {
|
||||
'user': unicode(request.user), # `django.contrib.auth.User` instance.
|
||||
'auth': unicode(request.auth), # None
|
||||
}
|
||||
return Response(content)
|
||||
</code></pre>
|
||||
<h2 id="unauthorized-and-forbidden-responses">Unauthorized and Forbidden responses</h2>
|
||||
<p>When an unauthenticated request is denied permission there are two different error codes that may be appropriate.</p>
|
||||
<ul>
|
||||
<li><a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2">HTTP 401 Unauthorized</a></li>
|
||||
<li><a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.4">HTTP 403 Permission Denied</a></li>
|
||||
</ul>
|
||||
<p>HTTP 401 responses must always include a <code>WWW-Authenticate</code> header, that instructs the client how to authenticate. HTTP 403 responses do not include the <code>WWW-Authenticate</code> header.</p>
|
||||
<p>The kind of response that will be used depends on the authentication scheme. Although multiple authentication schemes may be in use, only one scheme may be used to determine the type of response. <strong>The first authentication class set on the view is used when determining the type of response</strong>.</p>
|
||||
<p>Note that when a request may successfully authenticate, but still be denied permission to perform the request, in which case a <code>403 Permission Denied</code> response will always be used, regardless of the authentication scheme.</p>
|
||||
<h2 id="apache-mod_wsgi-specific-configuration">Apache mod_wsgi specific configuration</h2>
|
||||
<p>Note that if deploying to <a href="http://code.google.com/p/modwsgi/wiki/ConfigurationDirectives#WSGIPassAuthorization">Apache using mod_wsgi</a>, the authorization header is not passed through to a WSGI application by default, as it is assumed that authentication will be handled by Apache, rather than at an application level.</p>
|
||||
<p>If you are deploying to Apache, and using any non-session based authentication, you will need to explicitly configure mod_wsgi to pass the required headers through to the application. This can be done by specifying the <code>WSGIPassAuthorization</code> directive in the appropriate context and setting it to <code>'On'</code>.</p>
|
||||
<pre class="prettyprint lang-py"><code># this can go in either server config, virtual host, directory or .htaccess
|
||||
WSGIPassAuthorization On
|
||||
</code></pre>
|
||||
<hr />
|
||||
<h1 id="api-reference">API Reference</h1>
|
||||
<h2 id="basicauthentication">BasicAuthentication</h2>
|
||||
<p>This authentication scheme uses <a href="http://tools.ietf.org/html/rfc2617">HTTP Basic Authentication</a>, signed against a user's username and password. Basic authentication is generally only appropriate for testing.</p>
|
||||
<p>If successfully authenticated, <code>BasicAuthentication</code> provides the following credentials.</p>
|
||||
<ul>
|
||||
<li><code>request.user</code> will be a Django <code>User</code> instance.</li>
|
||||
<li><code>request.auth</code> will be <code>None</code>.</li>
|
||||
</ul>
|
||||
<p>Unauthenticated responses that are denied permission will result in an <code>HTTP 401 Unauthorized</code> response with an appropriate WWW-Authenticate header. For example:</p>
|
||||
<pre class="prettyprint lang-py"><code>WWW-Authenticate: Basic realm="api"
|
||||
</code></pre>
|
||||
<p><strong>Note:</strong> If you use <code>BasicAuthentication</code> in production you must ensure that your API is only available over <code>https</code>. You should also ensure that your API clients will always re-request the username and password at login, and will never store those details to persistent storage.</p>
|
||||
<h2 id="tokenauthentication">TokenAuthentication</h2>
|
||||
<p>This authentication scheme uses a simple token-based HTTP Authentication scheme. Token authentication is appropriate for client-server setups, such as native desktop and mobile clients. </p>
|
||||
<p>To use the <code>TokenAuthentication</code> scheme, include <code>rest_framework.authtoken</code> in your <code>INSTALLED_APPS</code> setting:</p>
|
||||
<pre class="prettyprint lang-py"><code>INSTALLED_APPS = (
|
||||
...
|
||||
'rest_framework.authtoken'
|
||||
)
|
||||
</code></pre>
|
||||
<p>Make sure to run <code>manage.py syncdb</code> after changing your settings. The <code>authtoken</code> database tables are managed by south (see <a href="#schema-migrations">Schema migrations</a> below).</p>
|
||||
<p>You'll also need to create tokens for your users.</p>
|
||||
<pre class="prettyprint lang-py"><code>from rest_framework.authtoken.models import Token
|
||||
|
||||
token = Token.objects.create(user=...)
|
||||
print token.key
|
||||
</code></pre>
|
||||
<p>For clients to authenticate, the token key should be included in the <code>Authorization</code> HTTP header. The key should be prefixed by the string literal "Token", with whitespace separating the two strings. For example:</p>
|
||||
<pre class="prettyprint lang-py"><code>Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b
|
||||
</code></pre>
|
||||
<p>If successfully authenticated, <code>TokenAuthentication</code> provides the following credentials.</p>
|
||||
<ul>
|
||||
<li><code>request.user</code> will be a Django <code>User</code> instance.</li>
|
||||
<li><code>request.auth</code> will be a <code>rest_framework.authtoken.models.BasicToken</code> instance.</li>
|
||||
</ul>
|
||||
<p>Unauthenticated responses that are denied permission will result in an <code>HTTP 401 Unauthorized</code> response with an appropriate WWW-Authenticate header. For example:</p>
|
||||
<pre class="prettyprint lang-py"><code>WWW-Authenticate: Token
|
||||
</code></pre>
|
||||
<p>The <code>curl</code> command line tool may be useful for testing token authenticated APIs. For example:</p>
|
||||
<pre class="prettyprint lang-py"><code>curl -X GET http://127.0.0.1:8000/api/example/ -H 'Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b'
|
||||
</code></pre>
|
||||
<hr />
|
||||
<p><strong>Note:</strong> If you use <code>TokenAuthentication</code> in production you must ensure that your API is only available over <code>https</code>.</p>
|
||||
<hr />
|
||||
<h4 id="generating-tokens">Generating Tokens</h4>
|
||||
<p>If you want every user to have an automatically generated Token, you can simply catch the User's <code>post_save</code> signal.</p>
|
||||
<pre class="prettyprint lang-py"><code>from django.dispatch import receiver
|
||||
from rest_framework.authtoken.models import Token
|
||||
|
||||
@receiver(post_save, sender=User)
|
||||
def create_auth_token(sender, instance=None, created=False, **kwargs):
|
||||
if created:
|
||||
Token.objects.create(user=instance)
|
||||
</code></pre>
|
||||
<p>Note that you'll want to ensure you place this code snippet in an installed <code>models.py</code> module, or some other location that will be imported by Django on startup.</p>
|
||||
<p>If you've already created some users, you can generate tokens for all existing users like this:</p>
|
||||
<pre class="prettyprint lang-py"><code>from django.contrib.auth.models import User
|
||||
from rest_framework.authtoken.models import Token
|
||||
|
||||
for user in User.objects.all():
|
||||
Token.objects.get_or_create(user=user)
|
||||
</code></pre>
|
||||
<p>When using <code>TokenAuthentication</code>, you may want to provide a mechanism for clients to obtain a token given the username and password. REST framework provides a built-in view to provide this behavior. To use it, add the <code>obtain_auth_token</code> view to your URLconf:</p>
|
||||
<pre class="prettyprint lang-py"><code>urlpatterns += patterns('',
|
||||
url(r'^api-token-auth/', 'rest_framework.authtoken.views.obtain_auth_token')
|
||||
)
|
||||
</code></pre>
|
||||
<p>Note that the URL part of the pattern can be whatever you want to use.</p>
|
||||
<p>The <code>obtain_auth_token</code> view will return a JSON response when valid <code>username</code> and <code>password</code> fields are POSTed to the view using form data or JSON:</p>
|
||||
<pre class="prettyprint lang-py"><code>{ 'token' : '9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b' }
|
||||
</code></pre>
|
||||
<p>Note that the default <code>obtain_auth_token</code> view explicitly uses JSON requests and responses, rather than using default renderer and parser classes in your settings. If you need a customized version of the <code>obtain_auth_token</code> view, you can do so by overriding the <code>ObtainAuthToken</code> view class, and using that in your url conf instead.</p>
|
||||
<h4 id="schema-migrations">Schema migrations</h4>
|
||||
<p>The <code>rest_framework.authtoken</code> app includes a south migration that will create the authtoken table.</p>
|
||||
<p>If you're using a <a href="https://docs.djangoproject.com/en/dev/topics/auth/customizing/#specifying-a-custom-user-model">custom user model</a> you'll need to make sure that any initial migration that creates the user table runs before the authtoken table is created.</p>
|
||||
<p>You can do so by inserting a <code>needed_by</code> attribute in your user migration:</p>
|
||||
<pre class="prettyprint lang-py"><code>class Migration:
|
||||
|
||||
needed_by = (
|
||||
('authtoken', '0001_initial'),
|
||||
)
|
||||
|
||||
def forwards(self):
|
||||
...
|
||||
</code></pre>
|
||||
<p>For more details, see the <a href="http://south.readthedocs.org/en/latest/dependencies.html">south documentation on dependencies</a>.</p>
|
||||
<p>Also note that if you're using a <code>post_save</code> signal to create tokens, then the first time you create the database tables, you'll need to ensure any migrations are run prior to creating any superusers. For example:</p>
|
||||
<pre class="prettyprint lang-py"><code>python manage.py syncdb --noinput # Won't create a superuser just yet, due to `--noinput`.
|
||||
python manage.py migrate
|
||||
python manage.py createsuperuser
|
||||
</code></pre>
|
||||
<h2 id="sessionauthentication">SessionAuthentication</h2>
|
||||
<p>This authentication scheme uses Django's default session backend for authentication. Session authentication is appropriate for AJAX clients that are running in the same session context as your website.</p>
|
||||
<p>If successfully authenticated, <code>SessionAuthentication</code> provides the following credentials.</p>
|
||||
<ul>
|
||||
<li><code>request.user</code> will be a Django <code>User</code> instance.</li>
|
||||
<li><code>request.auth</code> will be <code>None</code>.</li>
|
||||
</ul>
|
||||
<p>Unauthenticated responses that are denied permission will result in an <code>HTTP 403 Forbidden</code> response.</p>
|
||||
<p>If you're using an AJAX style API with SessionAuthentication, you'll need to make sure you include a valid CSRF token for any "unsafe" HTTP method calls, such as <code>PUT</code>, <code>PATCH</code>, <code>POST</code> or <code>DELETE</code> requests. See the <a href="https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax">Django CSRF documentation</a> for more details.</p>
|
||||
<h2 id="oauthauthentication">OAuthAuthentication</h2>
|
||||
<p>This authentication uses <a href="http://oauth.net/core/1.0a">OAuth 1.0a</a> authentication scheme. OAuth 1.0a provides signature validation which provides a reasonable level of security over plain non-HTTPS connections. However, it may also be considered more complicated than OAuth2, as it requires clients to sign their requests.</p>
|
||||
<p>This authentication class depends on the optional <code>django-oauth-plus</code> and <code>oauth2</code> packages. In order to make it work you must install these packages and add <code>oauth_provider</code> to your <code>INSTALLED_APPS</code>:</p>
|
||||
<pre class="prettyprint lang-py"><code>INSTALLED_APPS = (
|
||||
...
|
||||
`oauth_provider`,
|
||||
)
|
||||
</code></pre>
|
||||
<p>Don't forget to run <code>syncdb</code> once you've added the package.</p>
|
||||
<pre class="prettyprint lang-py"><code>python manage.py syncdb
|
||||
</code></pre>
|
||||
<h4 id="getting-started-with-django-oauth-plus">Getting started with django-oauth-plus</h4>
|
||||
<p>The OAuthAuthentication class only provides token verification and signature validation for requests. It doesn't provide authorization flow for your clients. You still need to implement your own views for accessing and authorizing tokens.</p>
|
||||
<p>The <code>django-oauth-plus</code> package provides simple foundation for classic 'three-legged' oauth flow. Please refer to <a href="http://code.larlet.fr/django-oauth-plus">the documentation</a> for more details.</p>
|
||||
<h2 id="oauth2authentication">OAuth2Authentication</h2>
|
||||
<p>This authentication uses <a href="http://tools.ietf.org/html/rfc6749">OAuth 2.0</a> authentication scheme. OAuth2 is more simple to work with than OAuth1, and provides much better security than simple token authentication. It is an unauthenticated scheme, and requires you to use an HTTPS connection.</p>
|
||||
<p>This authentication class depends on the optional <a href="https://github.com/caffeinehit/django-oauth2-provider">django-oauth2-provider</a> project. In order to make it work you must install this package and add <code>provider</code> and <code>provider.oauth2</code> to your <code>INSTALLED_APPS</code>:</p>
|
||||
<pre class="prettyprint lang-py"><code>INSTALLED_APPS = (
|
||||
...
|
||||
'provider',
|
||||
'provider.oauth2',
|
||||
)
|
||||
</code></pre>
|
||||
<p>Then add <code>OAuth2Authentication</code> to your global <code>DEFAULT_AUTHENTICATION</code> setting:</p>
|
||||
<pre class="prettyprint lang-py"><code>'DEFAULT_AUTHENTICATION_CLASSES': (
|
||||
'rest_framework.authentication.OAuth2Authentication',
|
||||
),
|
||||
</code></pre>
|
||||
<p>You must also include the following in your root <code>urls.py</code> module:</p>
|
||||
<pre class="prettyprint lang-py"><code>url(r'^oauth2/', include('provider.oauth2.urls', namespace='oauth2')),
|
||||
</code></pre>
|
||||
<p>Note that the <code>namespace='oauth2'</code> argument is required.</p>
|
||||
<p>Finally, sync your database.</p>
|
||||
<pre class="prettyprint lang-py"><code>python manage.py syncdb
|
||||
python manage.py migrate
|
||||
</code></pre>
|
||||
<hr />
|
||||
<p><strong>Note:</strong> If you use <code>OAuth2Authentication</code> in production you must ensure that your API is only available over <code>https</code>.</p>
|
||||
<hr />
|
||||
<h4 id="getting-started-with-django-oauth2-provider">Getting started with django-oauth2-provider</h4>
|
||||
<p>The <code>OAuth2Authentication</code> class only provides token verification for requests. It doesn't provide authorization flow for your clients.</p>
|
||||
<p>The OAuth 2 authorization flow is taken care by the <a href="https://github.com/caffeinehit/django-oauth2-provider">django-oauth2-provider</a> dependency. A walkthrough is given here, but for more details you should refer to <a href="https://django-oauth2-provider.readthedocs.org/en/latest/">the documentation</a>.</p>
|
||||
<p>To get started:</p>
|
||||
<h5 id="1-create-a-client">1. Create a client</h5>
|
||||
<p>You can create a client, either through the shell, or by using the Django admin.</p>
|
||||
<p>Go to the admin panel and create a new <code>Provider.Client</code> entry. It will create the <code>client_id</code> and <code>client_secret</code> properties for you.</p>
|
||||
<h5 id="2-request-an-access-token">2. Request an access token</h5>
|
||||
<p>To request an access token, submit a <code>POST</code> request to the url <code>/oauth2/access_token</code> with the following fields:</p>
|
||||
<ul>
|
||||
<li><code>client_id</code> the client id you've just configured at the previous step.</li>
|
||||
<li><code>client_secret</code> again configured at the previous step.</li>
|
||||
<li><code>username</code> the username with which you want to log in.</li>
|
||||
<li><code>password</code> well, that speaks for itself.</li>
|
||||
</ul>
|
||||
<p>You can use the command line to test that your local configuration is working:</p>
|
||||
<pre class="prettyprint lang-py"><code>curl -X POST -d "client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&grant_type=password&username=YOUR_USERNAME&password=YOUR_PASSWORD" http://localhost:8000/oauth2/access_token/
|
||||
</code></pre>
|
||||
<p>You should get a response that looks something like this:</p>
|
||||
<pre class="prettyprint lang-py"><code>{"access_token": "<your-access-token>", "scope": "read", "expires_in": 86399, "refresh_token": "<your-refresh-token>"}
|
||||
</code></pre>
|
||||
<h5 id="3-access-the-api">3. Access the API</h5>
|
||||
<p>The only thing needed to make the <code>OAuth2Authentication</code> class work is to insert the <code>access_token</code> you've received in the <code>Authorization</code> request header.</p>
|
||||
<p>The command line to test the authentication looks like:</p>
|
||||
<pre class="prettyprint lang-py"><code>curl -H "Authorization: Bearer <your-access-token>" http://localhost:8000/api/
|
||||
</code></pre>
|
||||
<h3 id="alternative-oauth-2-implementations">Alternative OAuth 2 implementations</h3>
|
||||
<p>Note that <a href="https://github.com/evonove/django-oauth-toolkit">Django OAuth Toolkit</a> is an alternative external package that also includes OAuth 2.0 support for REST framework.</p>
|
||||
<hr />
|
||||
<h1 id="custom-authentication">Custom authentication</h1>
|
||||
<p>To implement a custom authentication scheme, subclass <code>BaseAuthentication</code> and override the <code>.authenticate(self, request)</code> method. The method should return a two-tuple of <code>(user, auth)</code> if authentication succeeds, or <code>None</code> otherwise.</p>
|
||||
<p>In some circumstances instead of returning <code>None</code>, you may want to raise an <code>AuthenticationFailed</code> exception from the <code>.authenticate()</code> method.</p>
|
||||
<p>Typically the approach you should take is:</p>
|
||||
<ul>
|
||||
<li>If authentication is not attempted, return <code>None</code>. Any other authentication schemes also in use will still be checked.</li>
|
||||
<li>If authentication is attempted but fails, raise a <code>AuthenticationFailed</code> exception. An error response will be returned immediately, regardless of any permissions checks, and without checking any other authentication schemes.</li>
|
||||
</ul>
|
||||
<p>You <em>may</em> also override the <code>.authenticate_header(self, request)</code> method. If implemented, it should return a string that will be used as the value of the <code>WWW-Authenticate</code> header in a <code>HTTP 401 Unauthorized</code> response.</p>
|
||||
<p>If the <code>.authenticate_header()</code> method is not overridden, the authentication scheme will return <code>HTTP 403 Forbidden</code> responses when an unauthenticated request is denied access.</p>
|
||||
<h2 id="example">Example</h2>
|
||||
<p>The following example will authenticate any incoming request as the user given by the username in a custom request header named 'X_USERNAME'.</p>
|
||||
<pre class="prettyprint lang-py"><code>from django.contrib.auth.models import User
|
||||
from rest_framework import authentication
|
||||
from rest_framework import exceptions
|
||||
|
||||
class ExampleAuthentication(authentication.BaseAuthentication):
|
||||
def authenticate(self, request):
|
||||
username = request.META.get('X_USERNAME')
|
||||
if not username:
|
||||
return None
|
||||
|
||||
try:
|
||||
user = User.objects.get(username=username)
|
||||
except User.DoesNotExist:
|
||||
raise exceptions.AuthenticationFailed('No such user')
|
||||
|
||||
return (user, None)
|
||||
</code></pre>
|
||||
<hr />
|
||||
<h1 id="third-party-packages">Third party packages</h1>
|
||||
<p>The following third party packages are also available.</p>
|
||||
<h2 id="digest-authentication">Digest Authentication</h2>
|
||||
<p>HTTP digest authentication is a widely implemented scheme that was intended to replace HTTP basic authentication, and which provides a simple encrypted authentication mechanism. <a href="https://github.com/juanriaza">Juan Riaza</a> maintains the <a href="https://github.com/juanriaza/django-rest-framework-digestauth">djangorestframework-digestauth</a> package which provides HTTP digest authentication support for REST framework.</p>
|
||||
<h2 id="django-oauth-toolkit">Django OAuth Toolkit</h2>
|
||||
<p>The <a href="https://github.com/evonove/django-oauth-toolkit">Django OAuth Toolkit</a> package provides OAuth 2.0 support, and works with Python 2.7 and Python 3.3+. The package is maintained by <a href="https://github.com/evonove/">Evonove</a> and uses the excelllent <a href="https://github.com/idan/oauthlib">OAuthLib</a>. The package is well documented, and comes as a recommended alternative for OAuth 2.0 support.</p>
|
||||
<h2 id="django-oauth2-consumer">Django OAuth2 Consumer</h2>
|
||||
<p>The <a href="https://github.com/Rediker-Software/doac">Django OAuth2 Consumer</a> library from <a href="https://github.com/Rediker-Software">Rediker Software</a> is another package that provides <a href="https://github.com/Rediker-Software/doac/blob/master/docs/integrations.md#">OAuth 2.0 support for REST framework</a>. The package includes token scoping permissions on tokens, which allows finer-grained access to your API.</p>
|
||||
</div><!--/span-->
|
||||
</div><!--/row-->
|
||||
</div><!--/.fluid-container-->
|
||||
</div><!--/.body content-->
|
||||
|
||||
<div id="push"></div>
|
||||
</div><!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a></p>
|
||||
</footer>
|
||||
|
||||
<!-- Le javascript
|
||||
================================================== -->
|
||||
<!-- Placed at the end of the document so the pages load faster -->
|
||||
<script src="http://django-rest-framework.org/js/jquery-1.8.1-min.js"></script>
|
||||
<script src="http://django-rest-framework.org/js/prettify-1.0.js"></script>
|
||||
<script src="http://django-rest-framework.org/js/bootstrap-2.1.1-min.js"></script>
|
||||
<script>
|
||||
//$('.side-nav').scrollspy()
|
||||
var shiftWindow = function() { scrollBy(0, -50) };
|
||||
if (location.hash) shiftWindow();
|
||||
window.addEventListener("hashchange", shiftWindow);
|
||||
|
||||
$('.dropdown-menu').on('click touchstart', function(event) {
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
// Dynamically force sidenav to no higher than browser window
|
||||
$('.side-nav').css('max-height', window.innerHeight - 130);
|
||||
|
||||
$(function(){
|
||||
$(window).resize(function(){
|
||||
$('.side-nav').css('max-height', window.innerHeight - 130);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body></html>
|
||||
315
api-guide/content-negotiation.html
Normal file
315
api-guide/content-negotiation.html
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
<!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 - Content negotiation</title>
|
||||
<link href="http://django-rest-framework.org/img/favicon.ico" rel="icon" type="image/x-icon">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Django, API, REST, Content negotiation, Custom content negotiation">
|
||||
<meta name="author" content="Tom Christie">
|
||||
|
||||
<!-- Le styles -->
|
||||
<link href="http://django-rest-framework.org/css/prettify.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/bootstrap.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/bootstrap-responsive.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/default.css" rel="stylesheet">
|
||||
|
||||
<!-- 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]-->
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-18852272-2']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="prettyPrint()" class="content-negotiation-page">
|
||||
|
||||
<div class="wrapper">
|
||||
|
||||
<div class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container-fluid">
|
||||
<a class="repo-link btn btn-primary btn-small" href="https://github.com/tomchristie/django-rest-framework/tree/master">GitHub</a>
|
||||
<a class="repo-link btn btn-inverse btn-small " href="../api-guide/format-suffixes.html">Next <i class="icon-arrow-right icon-white"></i></a>
|
||||
<a class="repo-link btn btn-inverse btn-small " href="../api-guide/pagination.html"><i class="icon-arrow-left icon-white"></i> Previous</a>
|
||||
<a class="repo-link btn btn-inverse btn-small" href="#searchModal" data-toggle="modal"><i class="icon-search icon-white"></i> Search</a>
|
||||
<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>
|
||||
<a class="brand" href="http://django-rest-framework.org">Django REST framework</a>
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav">
|
||||
<li><a href="http://django-rest-framework.org">Home</a></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Tutorial <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/tutorial/quickstart.html">Quickstart</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/1-serialization.html">1 - Serialization</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/2-requests-and-responses.html">2 - Requests and responses</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/3-class-based-views.html">3 - Class based views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/4-authentication-and-permissions.html">4 - Authentication and permissions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/5-relationships-and-hyperlinked-apis.html">5 - Relationships and hyperlinked APIs</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/6-viewsets-and-routers.html">6 - Viewsets and routers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">API Guide <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/api-guide/requests.html">Requests</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/responses.html">Responses</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/views.html">Views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/generic-views.html">Generic views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/viewsets.html">Viewsets</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/routers.html">Routers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/parsers.html">Parsers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/renderers.html">Renderers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/serializers.html">Serializers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/fields.html">Serializer fields</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/relations.html">Serializer relations</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/authentication.html">Authentication</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/permissions.html">Permissions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/throttling.html">Throttling</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/filtering.html">Filtering</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/pagination.html">Pagination</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/content-negotiation.html">Content negotiation</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/format-suffixes.html">Format suffixes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/reverse.html">Returning URLs</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/exceptions.html">Exceptions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/status-codes.html">Status codes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/testing.html">Testing</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/settings.html">Settings</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Topics <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/topics/documenting-your-api.html">Documenting your API</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/ajax-csrf-cors.html">AJAX, CSRF & CORS</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/browser-enhancements.html">Browser enhancements</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/browsable-api.html">The Browsable API</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/rest-hypermedia-hateoas.html">REST, Hypermedia & HATEOAS</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/rest-framework-2-announcement.html">2.0 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/2.2-announcement.html">2.2 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/2.3-announcement.html">2.3 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/release-notes.html">Release Notes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/credits.html">Credits</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="nav pull-right">
|
||||
<!-- TODO
|
||||
<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>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="body-content">
|
||||
<div class="container-fluid">
|
||||
|
||||
<!-- Search Modal -->
|
||||
<div id="searchModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3 id="myModalLabel">Documentation search</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<!-- Custom google search -->
|
||||
<script>
|
||||
(function() {
|
||||
var cx = '015016005043623903336:rxraeohqk6w';
|
||||
var gcse = document.createElement('script');
|
||||
gcse.type = 'text/javascript';
|
||||
gcse.async = true;
|
||||
gcse.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') +
|
||||
'//www.google.com/cse/cse.js?cx=' + cx;
|
||||
var s = document.getElementsByTagName('script')[0];
|
||||
s.parentNode.insertBefore(gcse, s);
|
||||
})();
|
||||
</script>
|
||||
<gcse:search></gcse:search>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row-fluid">
|
||||
|
||||
<div class="span3">
|
||||
<!-- TODO
|
||||
<p style="margin-top: -12px">
|
||||
<a class="btn btn-mini btn-primary" style="width: 60px">« previous</a>
|
||||
<a class="btn btn-mini btn-primary" style="float: right; margin-right: 8px; width: 60px;">next »</a>
|
||||
</p>
|
||||
-->
|
||||
<div id="table-of-contents">
|
||||
<ul class="nav nav-list side-nav well sidebar-nav-fixed">
|
||||
<li class="main"><a href="#content-negotiation">Content negotiation</a></li>
|
||||
<li><a href="#determining-the-accepted-renderer">Determining the accepted renderer</a></li>
|
||||
<li class="main"><a href="#custom-content-negotiation">Custom content negotiation</a></li>
|
||||
<li><a href="#example">Example</a></li>
|
||||
<li><a href="#setting-the-content-negotiation">Setting the content negotiation</a></li>
|
||||
|
||||
<div>
|
||||
<hr>
|
||||
|
||||
<p><strong>The team behind REST framework are launching a new API service.</strong></p>
|
||||
|
||||
<p>If you want to be first in line when we start issuing invitations, please sign up here:</p>
|
||||
|
||||
<!-- Begin MailChimp Signup Form -->
|
||||
<link href="//cdn-images.mailchimp.com/embedcode/slim-081711.css" rel="stylesheet" type="text/css">
|
||||
<style type="text/css">
|
||||
#mc_embed_signup{background:#fff; clear:left; font:14px Helvetica,Arial,sans-serif; }
|
||||
/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
|
||||
We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
|
||||
</style>
|
||||
<div id="mc_embed_signup" style="background: rgb(245, 245, 245)">
|
||||
<form action="http://dabapps.us1.list-manage1.com/subscribe/post?u=cf73a9994eb5b8d8d461b5dfb&id=cb6af8e8bd" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>
|
||||
<!-- <label for="mce-EMAIL">Keep me posted!</label>
|
||||
--> <input style="width: 90%" type="email" value="" name="EMAIL" class="email" id="mce-EMAIL" placeholder="email address" required>
|
||||
<div class="clear"><input class="btn btn-success" type="submit" value="Yes, keep me posted!" name="subscribe" id="mc-embedded-subscribe" class="button"></div>
|
||||
</form>
|
||||
</div>
|
||||
</style></div>
|
||||
</ul>
|
||||
|
||||
|
||||
<!--End mc_embed_signup-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="main-content" class="span9">
|
||||
<p><a class="github" href="https://github.com/tomchristie/django-rest-framework/tree/master/rest_framework/negotiation.py"><span class="label label-info">negotiation.py</span></a></p>
|
||||
<h1 id="content-negotiation">Content negotiation</h1>
|
||||
<blockquote>
|
||||
<p>HTTP has provisions for several mechanisms for "content negotiation" - the process of selecting the best representation for a given response when there are multiple representations available.</p>
|
||||
<p>— <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html">RFC 2616</a>, Fielding et al.</p>
|
||||
</blockquote>
|
||||
<p>Content negotiation is the process of selecting one of multiple possible representations to return to a client, based on client or server preferences.</p>
|
||||
<h2 id="determining-the-accepted-renderer">Determining the accepted renderer</h2>
|
||||
<p>REST framework uses a simple style of content negotiation to determine which media type should be returned to a client, based on the available renderers, the priorities of each of those renderers, and the client's <code>Accept:</code> header. The style used is partly client-driven, and partly server-driven.</p>
|
||||
<ol>
|
||||
<li>More specific media types are given preference to less specific media types.</li>
|
||||
<li>If multiple media types have the same specificity, then preference is given to based on the ordering of the renderers configured for the given view.</li>
|
||||
</ol>
|
||||
<p>For example, given the following <code>Accept</code> header:</p>
|
||||
<pre class="prettyprint lang-py"><code>application/json; indent=4, application/json, application/yaml, text/html, */*
|
||||
</code></pre>
|
||||
<p>The priorities for each of the given media types would be:</p>
|
||||
<ul>
|
||||
<li><code>application/json; indent=4</code></li>
|
||||
<li><code>application/json</code>, <code>application/yaml</code> and <code>text/html</code></li>
|
||||
<li><code>*/*</code></li>
|
||||
</ul>
|
||||
<p>If the requested view was only configured with renderers for <code>YAML</code> and <code>HTML</code>, then REST framework would select whichever renderer was listed first in the <code>renderer_classes</code> list or <code>DEFAULT_RENDERER_CLASSES</code> setting.</p>
|
||||
<p>For more information on the <code>HTTP Accept</code> header, see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html">RFC 2616</a> </p>
|
||||
<hr />
|
||||
<p><strong>Note</strong>: "q" values are not taken into account by REST framework when determining preference. The use of "q" values negatively impacts caching, and in the author's opinion they are an unnecessary and overcomplicated approach to content negotiation.</p>
|
||||
<p>This is a valid approach as the HTTP spec deliberately underspecifies how a server should weight server-based preferences against client-based preferences.</p>
|
||||
<hr />
|
||||
<h1 id="custom-content-negotiation">Custom content negotiation</h1>
|
||||
<p>It's unlikely that you'll want to provide a custom content negotiation scheme for REST framework, but you can do so if needed. To implement a custom content negotiation scheme override <code>BaseContentNegotiation</code>.</p>
|
||||
<p>REST framework's content negotiation classes handle selection of both the appropriate parser for the request, and the appropriate renderer for the response, so you should implement both the <code>.select_parser(request, parsers)</code> and <code>.select_renderer(request, renderers, format_suffix)</code> methods.</p>
|
||||
<p>The <code>select_parser()</code> method should return one of the parser instances from the list of available parsers, or <code>None</code> if none of the parsers can handle the incoming request.</p>
|
||||
<p>The <code>select_renderer()</code> method should return a two-tuple of (renderer instance, media type), or raise a <code>NotAcceptable</code> exception.</p>
|
||||
<h2 id="example">Example</h2>
|
||||
<p>The following is a custom content negotiation class which ignores the client
|
||||
request when selecting the appropriate parser or renderer.</p>
|
||||
<pre class="prettyprint lang-py"><code>from rest_framework.negotiation import BaseContentNegotiation
|
||||
|
||||
class IgnoreClientContentNegotiation(BaseContentNegotiation):
|
||||
def select_parser(self, request, parsers):
|
||||
"""
|
||||
Select the first parser in the `.parser_classes` list.
|
||||
"""
|
||||
return parsers[0]
|
||||
|
||||
def select_renderer(self, request, renderers, format_suffix):
|
||||
"""
|
||||
Select the first renderer in the `.renderer_classes` list.
|
||||
"""
|
||||
return (renderers[0], renderers[0].media_type)
|
||||
</code></pre>
|
||||
<h2 id="setting-the-content-negotiation">Setting the content negotiation</h2>
|
||||
<p>The default content negotiation class may be set globally, using the <code>DEFAULT_CONTENT_NEGOTIATION_CLASS</code> setting. For example, the following settings would use our example <code>IgnoreClientContentNegotiation</code> class.</p>
|
||||
<pre class="prettyprint lang-py"><code>REST_FRAMEWORK = {
|
||||
'DEFAULT_CONTENT_NEGOTIATION_CLASS': 'myapp.negotiation.IgnoreClientContentNegotiation',
|
||||
}
|
||||
</code></pre>
|
||||
<p>You can also set the content negotiation used for an individual view, or viewset, using the <code>APIView</code> class based views.</p>
|
||||
<pre class="prettyprint lang-py"><code>from myapp.negotiation import IgnoreClientContentNegotiation
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
|
||||
class NoNegotiationView(APIView):
|
||||
"""
|
||||
An example view that does not perform content negotiation.
|
||||
"""
|
||||
content_negotiation_class = IgnoreClientContentNegotiation
|
||||
|
||||
def get(self, request, format=None):
|
||||
return Response({
|
||||
'accepted media type': request.accepted_renderer.media_type
|
||||
})
|
||||
</code></pre>
|
||||
</div><!--/span-->
|
||||
</div><!--/row-->
|
||||
</div><!--/.fluid-container-->
|
||||
</div><!--/.body content-->
|
||||
|
||||
<div id="push"></div>
|
||||
</div><!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a></p>
|
||||
</footer>
|
||||
|
||||
<!-- Le javascript
|
||||
================================================== -->
|
||||
<!-- Placed at the end of the document so the pages load faster -->
|
||||
<script src="http://django-rest-framework.org/js/jquery-1.8.1-min.js"></script>
|
||||
<script src="http://django-rest-framework.org/js/prettify-1.0.js"></script>
|
||||
<script src="http://django-rest-framework.org/js/bootstrap-2.1.1-min.js"></script>
|
||||
<script>
|
||||
//$('.side-nav').scrollspy()
|
||||
var shiftWindow = function() { scrollBy(0, -50) };
|
||||
if (location.hash) shiftWindow();
|
||||
window.addEventListener("hashchange", shiftWindow);
|
||||
|
||||
$('.dropdown-menu').on('click touchstart', function(event) {
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
// Dynamically force sidenav to no higher than browser window
|
||||
$('.side-nav').css('max-height', window.innerHeight - 130);
|
||||
|
||||
$(function(){
|
||||
$(window).resize(function(){
|
||||
$('.side-nav').css('max-height', window.innerHeight - 130);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body></html>
|
||||
345
api-guide/exceptions.html
Normal file
345
api-guide/exceptions.html
Normal file
|
|
@ -0,0 +1,345 @@
|
|||
<!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 - Exceptions</title>
|
||||
<link href="http://django-rest-framework.org/img/favicon.ico" rel="icon" type="image/x-icon">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Django, API, REST, Exceptions, API Reference">
|
||||
<meta name="author" content="Tom Christie">
|
||||
|
||||
<!-- Le styles -->
|
||||
<link href="http://django-rest-framework.org/css/prettify.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/bootstrap.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/bootstrap-responsive.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/default.css" rel="stylesheet">
|
||||
|
||||
<!-- 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]-->
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-18852272-2']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="prettyPrint()" class="exceptions-page">
|
||||
|
||||
<div class="wrapper">
|
||||
|
||||
<div class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container-fluid">
|
||||
<a class="repo-link btn btn-primary btn-small" href="https://github.com/tomchristie/django-rest-framework/tree/master">GitHub</a>
|
||||
<a class="repo-link btn btn-inverse btn-small " href="../api-guide/status-codes.html">Next <i class="icon-arrow-right icon-white"></i></a>
|
||||
<a class="repo-link btn btn-inverse btn-small " href="../api-guide/reverse.html"><i class="icon-arrow-left icon-white"></i> Previous</a>
|
||||
<a class="repo-link btn btn-inverse btn-small" href="#searchModal" data-toggle="modal"><i class="icon-search icon-white"></i> Search</a>
|
||||
<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>
|
||||
<a class="brand" href="http://django-rest-framework.org">Django REST framework</a>
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav">
|
||||
<li><a href="http://django-rest-framework.org">Home</a></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Tutorial <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/tutorial/quickstart.html">Quickstart</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/1-serialization.html">1 - Serialization</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/2-requests-and-responses.html">2 - Requests and responses</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/3-class-based-views.html">3 - Class based views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/4-authentication-and-permissions.html">4 - Authentication and permissions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/5-relationships-and-hyperlinked-apis.html">5 - Relationships and hyperlinked APIs</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/6-viewsets-and-routers.html">6 - Viewsets and routers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">API Guide <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/api-guide/requests.html">Requests</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/responses.html">Responses</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/views.html">Views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/generic-views.html">Generic views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/viewsets.html">Viewsets</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/routers.html">Routers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/parsers.html">Parsers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/renderers.html">Renderers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/serializers.html">Serializers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/fields.html">Serializer fields</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/relations.html">Serializer relations</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/authentication.html">Authentication</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/permissions.html">Permissions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/throttling.html">Throttling</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/filtering.html">Filtering</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/pagination.html">Pagination</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/content-negotiation.html">Content negotiation</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/format-suffixes.html">Format suffixes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/reverse.html">Returning URLs</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/exceptions.html">Exceptions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/status-codes.html">Status codes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/testing.html">Testing</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/settings.html">Settings</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Topics <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/topics/documenting-your-api.html">Documenting your API</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/ajax-csrf-cors.html">AJAX, CSRF & CORS</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/browser-enhancements.html">Browser enhancements</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/browsable-api.html">The Browsable API</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/rest-hypermedia-hateoas.html">REST, Hypermedia & HATEOAS</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/rest-framework-2-announcement.html">2.0 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/2.2-announcement.html">2.2 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/2.3-announcement.html">2.3 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/release-notes.html">Release Notes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/credits.html">Credits</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="nav pull-right">
|
||||
<!-- TODO
|
||||
<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>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="body-content">
|
||||
<div class="container-fluid">
|
||||
|
||||
<!-- Search Modal -->
|
||||
<div id="searchModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3 id="myModalLabel">Documentation search</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<!-- Custom google search -->
|
||||
<script>
|
||||
(function() {
|
||||
var cx = '015016005043623903336:rxraeohqk6w';
|
||||
var gcse = document.createElement('script');
|
||||
gcse.type = 'text/javascript';
|
||||
gcse.async = true;
|
||||
gcse.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') +
|
||||
'//www.google.com/cse/cse.js?cx=' + cx;
|
||||
var s = document.getElementsByTagName('script')[0];
|
||||
s.parentNode.insertBefore(gcse, s);
|
||||
})();
|
||||
</script>
|
||||
<gcse:search></gcse:search>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row-fluid">
|
||||
|
||||
<div class="span3">
|
||||
<!-- TODO
|
||||
<p style="margin-top: -12px">
|
||||
<a class="btn btn-mini btn-primary" style="width: 60px">« previous</a>
|
||||
<a class="btn btn-mini btn-primary" style="float: right; margin-right: 8px; width: 60px;">next »</a>
|
||||
</p>
|
||||
-->
|
||||
<div id="table-of-contents">
|
||||
<ul class="nav nav-list side-nav well sidebar-nav-fixed">
|
||||
<li class="main"><a href="#exceptions">Exceptions</a></li>
|
||||
<li><a href="#exception-handling-in-rest-framework-views">Exception handling in REST framework views</a></li>
|
||||
<li><a href="#custom-exception-handling">Custom exception handling</a></li>
|
||||
<li class="main"><a href="#api-reference">API Reference</a></li>
|
||||
<li><a href="#apiexception">APIException</a></li>
|
||||
<li><a href="#parseerror">ParseError</a></li>
|
||||
<li><a href="#authenticationfailed">AuthenticationFailed</a></li>
|
||||
<li><a href="#notauthenticated">NotAuthenticated</a></li>
|
||||
<li><a href="#permissiondenied">PermissionDenied</a></li>
|
||||
<li><a href="#methodnotallowed">MethodNotAllowed</a></li>
|
||||
<li><a href="#unsupportedmediatype">UnsupportedMediaType</a></li>
|
||||
<li><a href="#throttled">Throttled</a></li>
|
||||
|
||||
<div>
|
||||
<hr>
|
||||
|
||||
<p><strong>The team behind REST framework are launching a new API service.</strong></p>
|
||||
|
||||
<p>If you want to be first in line when we start issuing invitations, please sign up here:</p>
|
||||
|
||||
<!-- Begin MailChimp Signup Form -->
|
||||
<link href="//cdn-images.mailchimp.com/embedcode/slim-081711.css" rel="stylesheet" type="text/css">
|
||||
<style type="text/css">
|
||||
#mc_embed_signup{background:#fff; clear:left; font:14px Helvetica,Arial,sans-serif; }
|
||||
/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
|
||||
We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
|
||||
</style>
|
||||
<div id="mc_embed_signup" style="background: rgb(245, 245, 245)">
|
||||
<form action="http://dabapps.us1.list-manage1.com/subscribe/post?u=cf73a9994eb5b8d8d461b5dfb&id=cb6af8e8bd" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>
|
||||
<!-- <label for="mce-EMAIL">Keep me posted!</label>
|
||||
--> <input style="width: 90%" type="email" value="" name="EMAIL" class="email" id="mce-EMAIL" placeholder="email address" required>
|
||||
<div class="clear"><input class="btn btn-success" type="submit" value="Yes, keep me posted!" name="subscribe" id="mc-embedded-subscribe" class="button"></div>
|
||||
</form>
|
||||
</div>
|
||||
</style></div>
|
||||
</ul>
|
||||
|
||||
|
||||
<!--End mc_embed_signup-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="main-content" class="span9">
|
||||
<p><a class="github" href="https://github.com/tomchristie/django-rest-framework/tree/master/rest_framework/exceptions.py"><span class="label label-info">exceptions.py</span></a></p>
|
||||
<h1 id="exceptions">Exceptions</h1>
|
||||
<blockquote>
|
||||
<p>Exceptions… allow error handling to be organized cleanly in a central or high-level place within the program structure.</p>
|
||||
<p>— Doug Hellmann, <a href="http://www.doughellmann.com/articles/how-tos/python-exception-handling/index.html">Python Exception Handling Techniques</a></p>
|
||||
</blockquote>
|
||||
<h2 id="exception-handling-in-rest-framework-views">Exception handling in REST framework views</h2>
|
||||
<p>REST framework's views handle various exceptions, and deal with returning appropriate error responses.</p>
|
||||
<p>The handled exceptions are:</p>
|
||||
<ul>
|
||||
<li>Subclasses of <code>APIException</code> raised inside REST framework.</li>
|
||||
<li>Django's <code>Http404</code> exception.</li>
|
||||
<li>Django's <code>PermissionDenied</code> exception.</li>
|
||||
</ul>
|
||||
<p>In each case, REST framework will return a response with an appropriate status code and content-type. The body of the response will include any additional details regarding the nature of the error.</p>
|
||||
<p>By default all error responses will include a key <code>details</code> in the body of the response, but other keys may also be included.</p>
|
||||
<p>For example, the following request:</p>
|
||||
<pre class="prettyprint lang-py"><code>DELETE http://api.example.com/foo/bar HTTP/1.1
|
||||
Accept: application/json
|
||||
</code></pre>
|
||||
<p>Might receive an error response indicating that the <code>DELETE</code> method is not allowed on that resource:</p>
|
||||
<pre class="prettyprint lang-py"><code>HTTP/1.1 405 Method Not Allowed
|
||||
Content-Type: application/json
|
||||
Content-Length: 42
|
||||
|
||||
{"detail": "Method 'DELETE' not allowed."}
|
||||
</code></pre>
|
||||
<h2 id="custom-exception-handling">Custom exception handling</h2>
|
||||
<p>You can implement custom exception handling by creating a handler function that converts exceptions raised in your API views into response objects. This allows you to control the style of error responses used by your API.</p>
|
||||
<p>The function must take a single argument, which is the exception to be handled, and should either return a <code>Response</code> object, or return <code>None</code> if the exception cannot be handled. If the handler returns <code>None</code> then the exception will be re-raised and Django will return a standard HTTP 500 'server error' response.</p>
|
||||
<p>For example, you might want to ensure that all error responses include the HTTP status code in the body of the response, like so:</p>
|
||||
<pre class="prettyprint lang-py"><code>HTTP/1.1 405 Method Not Allowed
|
||||
Content-Type: application/json
|
||||
Content-Length: 62
|
||||
|
||||
{"status_code": 405, "detail": "Method 'DELETE' not allowed."}
|
||||
</code></pre>
|
||||
<p>In order to alter the style of the response, you could write the following custom exception handler:</p>
|
||||
<pre class="prettyprint lang-py"><code>from rest_framework.views import exception_handler
|
||||
|
||||
def custom_exception_handler(exc):
|
||||
# Call REST framework's default exception handler first,
|
||||
# to get the standard error response.
|
||||
response = exception_handler(exc)
|
||||
|
||||
# Now add the HTTP status code to the response.
|
||||
if response is not None:
|
||||
response.data['status_code'] = response.status_code
|
||||
|
||||
return response
|
||||
</code></pre>
|
||||
<p>The exception handler must also be configured in your settings, using the <code>EXCEPTION_HANDLER</code> setting key. For example:</p>
|
||||
<pre class="prettyprint lang-py"><code>REST_FRAMEWORK = {
|
||||
'EXCEPTION_HANDLER': 'my_project.my_app.utils.custom_exception_handler'
|
||||
}
|
||||
</code></pre>
|
||||
<p>If not specified, the <code>'EXCEPTION_HANDLER'</code> setting defaults to the standard exception handler provided by REST framework:</p>
|
||||
<pre class="prettyprint lang-py"><code>REST_FRAMEWORK = {
|
||||
'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler'
|
||||
}
|
||||
</code></pre>
|
||||
<p>Note that the exception handler will only be called for responses generated by raised exceptions. It will not be used for any responses returned directly by the view, such as the <code>HTTP_400_BAD_REQUEST</code> responses that are returned by the generic views when serializer validation fails.</p>
|
||||
<hr />
|
||||
<h1 id="api-reference">API Reference</h1>
|
||||
<h2 id="apiexception">APIException</h2>
|
||||
<p><strong>Signature:</strong> <code>APIException()</code></p>
|
||||
<p>The <strong>base class</strong> for all exceptions raised inside REST framework.</p>
|
||||
<p>To provide a custom exception, subclass <code>APIException</code> and set the <code>.status_code</code> and <code>.detail</code> properties on the class.</p>
|
||||
<h2 id="parseerror">ParseError</h2>
|
||||
<p><strong>Signature:</strong> <code>ParseError(detail=None)</code></p>
|
||||
<p>Raised if the request contains malformed data when accessing <code>request.DATA</code> or <code>request.FILES</code>.</p>
|
||||
<p>By default this exception results in a response with the HTTP status code "400 Bad Request".</p>
|
||||
<h2 id="authenticationfailed">AuthenticationFailed</h2>
|
||||
<p><strong>Signature:</strong> <code>AuthenticationFailed(detail=None)</code></p>
|
||||
<p>Raised when an incoming request includes incorrect authentication.</p>
|
||||
<p>By default this exception results in a response with the HTTP status code "401 Unauthenticated", but it may also result in a "403 Forbidden" response, depending on the authentication scheme in use. See the <a href="authentication.html">authentication documentation</a> for more details.</p>
|
||||
<h2 id="notauthenticated">NotAuthenticated</h2>
|
||||
<p><strong>Signature:</strong> <code>NotAuthenticated(detail=None)</code></p>
|
||||
<p>Raised when an unauthenticated request fails the permission checks.</p>
|
||||
<p>By default this exception results in a response with the HTTP status code "401 Unauthenticated", but it may also result in a "403 Forbidden" response, depending on the authentication scheme in use. See the <a href="authentication.html">authentication documentation</a> for more details.</p>
|
||||
<h2 id="permissiondenied">PermissionDenied</h2>
|
||||
<p><strong>Signature:</strong> <code>PermissionDenied(detail=None)</code></p>
|
||||
<p>Raised when an authenticated request fails the permission checks.</p>
|
||||
<p>By default this exception results in a response with the HTTP status code "403 Forbidden".</p>
|
||||
<h2 id="methodnotallowed">MethodNotAllowed</h2>
|
||||
<p><strong>Signature:</strong> <code>MethodNotAllowed(method, detail=None)</code></p>
|
||||
<p>Raised when an incoming request occurs that does not map to a handler method on the view.</p>
|
||||
<p>By default this exception results in a response with the HTTP status code "405 Method Not Allowed".</p>
|
||||
<h2 id="unsupportedmediatype">UnsupportedMediaType</h2>
|
||||
<p><strong>Signature:</strong> <code>UnsupportedMediaType(media_type, detail=None)</code></p>
|
||||
<p>Raised if there are no parsers that can handle the content type of the request data when accessing <code>request.DATA</code> or <code>request.FILES</code>.</p>
|
||||
<p>By default this exception results in a response with the HTTP status code "415 Unsupported Media Type".</p>
|
||||
<h2 id="throttled">Throttled</h2>
|
||||
<p><strong>Signature:</strong> <code>Throttled(wait=None, detail=None)</code></p>
|
||||
<p>Raised when an incoming request fails the throttling checks.</p>
|
||||
<p>By default this exception results in a response with the HTTP status code "429 Too Many Requests".</p>
|
||||
</div><!--/span-->
|
||||
</div><!--/row-->
|
||||
</div><!--/.fluid-container-->
|
||||
</div><!--/.body content-->
|
||||
|
||||
<div id="push"></div>
|
||||
</div><!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a></p>
|
||||
</footer>
|
||||
|
||||
<!-- Le javascript
|
||||
================================================== -->
|
||||
<!-- Placed at the end of the document so the pages load faster -->
|
||||
<script src="http://django-rest-framework.org/js/jquery-1.8.1-min.js"></script>
|
||||
<script src="http://django-rest-framework.org/js/prettify-1.0.js"></script>
|
||||
<script src="http://django-rest-framework.org/js/bootstrap-2.1.1-min.js"></script>
|
||||
<script>
|
||||
//$('.side-nav').scrollspy()
|
||||
var shiftWindow = function() { scrollBy(0, -50) };
|
||||
if (location.hash) shiftWindow();
|
||||
window.addEventListener("hashchange", shiftWindow);
|
||||
|
||||
$('.dropdown-menu').on('click touchstart', function(event) {
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
// Dynamically force sidenav to no higher than browser window
|
||||
$('.side-nav').css('max-height', window.innerHeight - 130);
|
||||
|
||||
$(function(){
|
||||
$(window).resize(function(){
|
||||
$('.side-nav').css('max-height', window.innerHeight - 130);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body></html>
|
||||
487
api-guide/fields.html
Normal file
487
api-guide/fields.html
Normal file
|
|
@ -0,0 +1,487 @@
|
|||
<!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 - Serializer fields</title>
|
||||
<link href="http://django-rest-framework.org/img/favicon.ico" rel="icon" type="image/x-icon">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Django, API, REST, Serializer fields, Generic Fields, Typed Fields, Custom fields">
|
||||
<meta name="author" content="Tom Christie">
|
||||
|
||||
<!-- Le styles -->
|
||||
<link href="http://django-rest-framework.org/css/prettify.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/bootstrap.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/bootstrap-responsive.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/default.css" rel="stylesheet">
|
||||
|
||||
<!-- 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]-->
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-18852272-2']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="prettyPrint()" class="fields-page">
|
||||
|
||||
<div class="wrapper">
|
||||
|
||||
<div class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container-fluid">
|
||||
<a class="repo-link btn btn-primary btn-small" href="https://github.com/tomchristie/django-rest-framework/tree/master">GitHub</a>
|
||||
<a class="repo-link btn btn-inverse btn-small " href="../api-guide/relations.html">Next <i class="icon-arrow-right icon-white"></i></a>
|
||||
<a class="repo-link btn btn-inverse btn-small " href="../api-guide/serializers.html"><i class="icon-arrow-left icon-white"></i> Previous</a>
|
||||
<a class="repo-link btn btn-inverse btn-small" href="#searchModal" data-toggle="modal"><i class="icon-search icon-white"></i> Search</a>
|
||||
<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>
|
||||
<a class="brand" href="http://django-rest-framework.org">Django REST framework</a>
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav">
|
||||
<li><a href="http://django-rest-framework.org">Home</a></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Tutorial <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/tutorial/quickstart.html">Quickstart</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/1-serialization.html">1 - Serialization</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/2-requests-and-responses.html">2 - Requests and responses</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/3-class-based-views.html">3 - Class based views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/4-authentication-and-permissions.html">4 - Authentication and permissions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/5-relationships-and-hyperlinked-apis.html">5 - Relationships and hyperlinked APIs</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/6-viewsets-and-routers.html">6 - Viewsets and routers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">API Guide <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/api-guide/requests.html">Requests</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/responses.html">Responses</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/views.html">Views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/generic-views.html">Generic views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/viewsets.html">Viewsets</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/routers.html">Routers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/parsers.html">Parsers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/renderers.html">Renderers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/serializers.html">Serializers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/fields.html">Serializer fields</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/relations.html">Serializer relations</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/authentication.html">Authentication</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/permissions.html">Permissions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/throttling.html">Throttling</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/filtering.html">Filtering</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/pagination.html">Pagination</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/content-negotiation.html">Content negotiation</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/format-suffixes.html">Format suffixes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/reverse.html">Returning URLs</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/exceptions.html">Exceptions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/status-codes.html">Status codes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/testing.html">Testing</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/settings.html">Settings</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Topics <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/topics/documenting-your-api.html">Documenting your API</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/ajax-csrf-cors.html">AJAX, CSRF & CORS</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/browser-enhancements.html">Browser enhancements</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/browsable-api.html">The Browsable API</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/rest-hypermedia-hateoas.html">REST, Hypermedia & HATEOAS</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/rest-framework-2-announcement.html">2.0 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/2.2-announcement.html">2.2 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/2.3-announcement.html">2.3 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/release-notes.html">Release Notes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/credits.html">Credits</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="nav pull-right">
|
||||
<!-- TODO
|
||||
<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>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="body-content">
|
||||
<div class="container-fluid">
|
||||
|
||||
<!-- Search Modal -->
|
||||
<div id="searchModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3 id="myModalLabel">Documentation search</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<!-- Custom google search -->
|
||||
<script>
|
||||
(function() {
|
||||
var cx = '015016005043623903336:rxraeohqk6w';
|
||||
var gcse = document.createElement('script');
|
||||
gcse.type = 'text/javascript';
|
||||
gcse.async = true;
|
||||
gcse.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') +
|
||||
'//www.google.com/cse/cse.js?cx=' + cx;
|
||||
var s = document.getElementsByTagName('script')[0];
|
||||
s.parentNode.insertBefore(gcse, s);
|
||||
})();
|
||||
</script>
|
||||
<gcse:search></gcse:search>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row-fluid">
|
||||
|
||||
<div class="span3">
|
||||
<!-- TODO
|
||||
<p style="margin-top: -12px">
|
||||
<a class="btn btn-mini btn-primary" style="width: 60px">« previous</a>
|
||||
<a class="btn btn-mini btn-primary" style="float: right; margin-right: 8px; width: 60px;">next »</a>
|
||||
</p>
|
||||
-->
|
||||
<div id="table-of-contents">
|
||||
<ul class="nav nav-list side-nav well sidebar-nav-fixed">
|
||||
<li class="main"><a href="#serializer-fields">Serializer fields</a></li>
|
||||
<li><a href="#core-arguments">Core arguments</a></li>
|
||||
<li class="main"><a href="#generic-fields">Generic Fields</a></li>
|
||||
<li><a href="#field">Field</a></li>
|
||||
<li><a href="#writablefield">WritableField</a></li>
|
||||
<li><a href="#modelfield">ModelField</a></li>
|
||||
<li><a href="#serializermethodfield">SerializerMethodField</a></li>
|
||||
<li class="main"><a href="#typed-fields">Typed Fields</a></li>
|
||||
<li><a href="#booleanfield">BooleanField</a></li>
|
||||
<li><a href="#charfield">CharField</a></li>
|
||||
<li><a href="#urlfield">URLField</a></li>
|
||||
<li><a href="#slugfield">SlugField</a></li>
|
||||
<li><a href="#choicefield">ChoiceField</a></li>
|
||||
<li><a href="#emailfield">EmailField</a></li>
|
||||
<li><a href="#regexfield">RegexField</a></li>
|
||||
<li><a href="#datetimefield">DateTimeField</a></li>
|
||||
<li><a href="#datefield">DateField</a></li>
|
||||
<li><a href="#timefield">TimeField</a></li>
|
||||
<li><a href="#integerfield">IntegerField</a></li>
|
||||
<li><a href="#floatfield">FloatField</a></li>
|
||||
<li><a href="#decimalfield">DecimalField</a></li>
|
||||
<li><a href="#filefield">FileField</a></li>
|
||||
<li><a href="#imagefield">ImageField</a></li>
|
||||
<li class="main"><a href="#custom-fields">Custom fields</a></li>
|
||||
<li><a href="#examples">Examples</a></li>
|
||||
|
||||
<div>
|
||||
<hr>
|
||||
|
||||
<p><strong>The team behind REST framework are launching a new API service.</strong></p>
|
||||
|
||||
<p>If you want to be first in line when we start issuing invitations, please sign up here:</p>
|
||||
|
||||
<!-- Begin MailChimp Signup Form -->
|
||||
<link href="//cdn-images.mailchimp.com/embedcode/slim-081711.css" rel="stylesheet" type="text/css">
|
||||
<style type="text/css">
|
||||
#mc_embed_signup{background:#fff; clear:left; font:14px Helvetica,Arial,sans-serif; }
|
||||
/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
|
||||
We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
|
||||
</style>
|
||||
<div id="mc_embed_signup" style="background: rgb(245, 245, 245)">
|
||||
<form action="http://dabapps.us1.list-manage1.com/subscribe/post?u=cf73a9994eb5b8d8d461b5dfb&id=cb6af8e8bd" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>
|
||||
<!-- <label for="mce-EMAIL">Keep me posted!</label>
|
||||
--> <input style="width: 90%" type="email" value="" name="EMAIL" class="email" id="mce-EMAIL" placeholder="email address" required>
|
||||
<div class="clear"><input class="btn btn-success" type="submit" value="Yes, keep me posted!" name="subscribe" id="mc-embedded-subscribe" class="button"></div>
|
||||
</form>
|
||||
</div>
|
||||
</style></div>
|
||||
</ul>
|
||||
|
||||
|
||||
<!--End mc_embed_signup-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="main-content" class="span9">
|
||||
<p><a class="github" href="https://github.com/tomchristie/django-rest-framework/tree/master/rest_framework/fields.py"><span class="label label-info">fields.py</span></a></p>
|
||||
<h1 id="serializer-fields">Serializer fields</h1>
|
||||
<blockquote>
|
||||
<p>Each field in a Form class is responsible not only for validating data, but also for "cleaning" it — normalizing it to a consistent format. </p>
|
||||
<p>— <a href="https://docs.djangoproject.com/en/dev/ref/forms/api/#django.forms.Form.cleaned_data">Django documentation</a></p>
|
||||
</blockquote>
|
||||
<p>Serializer fields handle converting between primitive values and internal datatypes. They also deal with validating input values, as well as retrieving and setting the values from their parent objects.</p>
|
||||
<hr />
|
||||
<p><strong>Note:</strong> The serializer fields are declared in fields.py, but by convention you should import them using <code>from rest_framework import serializers</code> and refer to fields as <code>serializers.<FieldName></code>.</p>
|
||||
<hr />
|
||||
<h2 id="core-arguments">Core arguments</h2>
|
||||
<p>Each serializer field class constructor takes at least these arguments. Some Field classes take additional, field-specific arguments, but the following should always be accepted:</p>
|
||||
<h3 id="source"><code>source</code></h3>
|
||||
<p>The name of the attribute that will be used to populate the field. May be a method that only takes a <code>self</code> argument, such as <code>Field(source='get_absolute_url')</code>, or may use dotted notation to traverse attributes, such as <code>Field(source='user.email')</code>.</p>
|
||||
<p>The value <code>source='*'</code> has a special meaning, and is used to indicate that the entire object should be passed through to the field. This can be useful for creating nested representations. (See the implementation of the <code>PaginationSerializer</code> class for an example.)</p>
|
||||
<p>Defaults to the name of the field.</p>
|
||||
<h3 id="read_only"><code>read_only</code></h3>
|
||||
<p>Set this to <code>True</code> to ensure that the field is used when serializing a representation, but is not used when updating an instance during deserialization.</p>
|
||||
<p>Defaults to <code>False</code></p>
|
||||
<h3 id="required"><code>required</code></h3>
|
||||
<p>Normally an error will be raised if a field is not supplied during deserialization.
|
||||
Set to false if this field is not required to be present during deserialization.</p>
|
||||
<p>Defaults to <code>True</code>.</p>
|
||||
<h3 id="default"><code>default</code></h3>
|
||||
<p>If set, this gives the default value that will be used for the field if none is supplied. If not set the default behavior is to not populate the attribute at all. </p>
|
||||
<p>May be set to a function or other callable, in which case the value will be evaluated each time it is used.</p>
|
||||
<h3 id="validators"><code>validators</code></h3>
|
||||
<p>A list of Django validators that should be used to validate deserialized values.</p>
|
||||
<h3 id="error_messages"><code>error_messages</code></h3>
|
||||
<p>A dictionary of error codes to error messages.</p>
|
||||
<h3 id="widget"><code>widget</code></h3>
|
||||
<p>Used only if rendering the field to HTML.
|
||||
This argument sets the widget that should be used to render the field.</p>
|
||||
<h3 id="label"><code>label</code></h3>
|
||||
<p>A short text string that may be used as the name of the field in HTML form fields or other descriptive elements.</p>
|
||||
<h3 id="help_text"><code>help_text</code></h3>
|
||||
<p>A text string that may be used as a description of the field in HTML form fields or other descriptive elements.</p>
|
||||
<hr />
|
||||
<h1 id="generic-fields">Generic Fields</h1>
|
||||
<p>These generic fields are used for representing arbitrary model fields or the output of model methods.</p>
|
||||
<h2 id="field">Field</h2>
|
||||
<p>A generic, <strong>read-only</strong> field. You can use this field for any attribute that does not need to support write operations.</p>
|
||||
<p>For example, using the following model.</p>
|
||||
<pre class="prettyprint lang-py"><code>from django.db import models
|
||||
from django.utils.timezone import now
|
||||
|
||||
class Account(models.Model):
|
||||
owner = models.ForeignKey('auth.user')
|
||||
name = models.CharField(max_length=100)
|
||||
created = models.DateTimeField(auto_now_add=True)
|
||||
payment_expiry = models.DateTimeField()
|
||||
|
||||
def has_expired(self):
|
||||
return now() > self.payment_expiry
|
||||
</code></pre>
|
||||
<p>A serializer definition that looked like this:</p>
|
||||
<pre class="prettyprint lang-py"><code>from rest_framework import serializers
|
||||
|
||||
class AccountSerializer(serializers.HyperlinkedModelSerializer):
|
||||
expired = serializers.Field(source='has_expired')
|
||||
|
||||
class Meta:
|
||||
fields = ('url', 'owner', 'name', 'expired')
|
||||
</code></pre>
|
||||
<p>Would produce output similar to:</p>
|
||||
<pre class="prettyprint lang-py"><code>{
|
||||
'url': 'http://example.com/api/accounts/3/',
|
||||
'owner': 'http://example.com/api/users/12/',
|
||||
'name': 'FooCorp business account',
|
||||
'expired': True
|
||||
}
|
||||
</code></pre>
|
||||
<p>By default, the <code>Field</code> class will perform a basic translation of the source value into primitive datatypes, falling back to unicode representations of complex datatypes when necessary.</p>
|
||||
<p>You can customize this behavior by overriding the <code>.to_native(self, value)</code> method.</p>
|
||||
<h2 id="writablefield">WritableField</h2>
|
||||
<p>A field that supports both read and write operations. By itself <code>WritableField</code> does not perform any translation of input values into a given type. You won't typically use this field directly, but you may want to override it and implement the <code>.to_native(self, value)</code> and <code>.from_native(self, value)</code> methods.</p>
|
||||
<h2 id="modelfield">ModelField</h2>
|
||||
<p>A generic field that can be tied to any arbitrary model field. The <code>ModelField</code> class delegates the task of serialization/deserialization to it's associated model field. This field can be used to create serializer fields for custom model fields, without having to create a new custom serializer field.</p>
|
||||
<p>The <code>ModelField</code> class is generally intended for internal use, but can be used by your API if needed. In order to properly instantiate a <code>ModelField</code>, it must be passed a field that is attached to an instantiated model. For example: <code>ModelField(model_field=MyModel()._meta.get_field('custom_field'))</code></p>
|
||||
<p><strong>Signature:</strong> <code>ModelField(model_field=<Django ModelField instance>)</code></p>
|
||||
<h2 id="serializermethodfield">SerializerMethodField</h2>
|
||||
<p>This is a read-only field. It gets its value by calling a method on the serializer class it is attached to. It can be used to add any sort of data to the serialized representation of your object. The field's constructor accepts a single argument, which is the name of the method on the serializer to be called. The method should accept a single argument (in addition to <code>self</code>), which is the object being serialized. It should return whatever you want to be included in the serialized representation of the object. For example:</p>
|
||||
<pre class="prettyprint lang-py"><code>from django.contrib.auth.models import User
|
||||
from django.utils.timezone import now
|
||||
from rest_framework import serializers
|
||||
|
||||
class UserSerializer(serializers.ModelSerializer):
|
||||
days_since_joined = serializers.SerializerMethodField('get_days_since_joined')
|
||||
|
||||
class Meta:
|
||||
model = User
|
||||
|
||||
def get_days_since_joined(self, obj):
|
||||
return (now() - obj.date_joined).days
|
||||
</code></pre>
|
||||
<hr />
|
||||
<h1 id="typed-fields">Typed Fields</h1>
|
||||
<p>These fields represent basic datatypes, and support both reading and writing values.</p>
|
||||
<h2 id="booleanfield">BooleanField</h2>
|
||||
<p>A Boolean representation.</p>
|
||||
<p>Corresponds to <code>django.db.models.fields.BooleanField</code>.</p>
|
||||
<h2 id="charfield">CharField</h2>
|
||||
<p>A text representation, optionally validates the text to be shorter than <code>max_length</code> and longer than <code>min_length</code>.</p>
|
||||
<p>Corresponds to <code>django.db.models.fields.CharField</code>
|
||||
or <code>django.db.models.fields.TextField</code>.</p>
|
||||
<p><strong>Signature:</strong> <code>CharField(max_length=None, min_length=None)</code></p>
|
||||
<h2 id="urlfield">URLField</h2>
|
||||
<p>Corresponds to <code>django.db.models.fields.URLField</code>. Uses Django's <code>django.core.validators.URLValidator</code> for validation.</p>
|
||||
<p><strong>Signature:</strong> <code>CharField(max_length=200, min_length=None)</code></p>
|
||||
<h2 id="slugfield">SlugField</h2>
|
||||
<p>Corresponds to <code>django.db.models.fields.SlugField</code>.</p>
|
||||
<p><strong>Signature:</strong> <code>CharField(max_length=50, min_length=None)</code></p>
|
||||
<h2 id="choicefield">ChoiceField</h2>
|
||||
<p>A field that can accept a value out of a limited set of choices.</p>
|
||||
<h2 id="emailfield">EmailField</h2>
|
||||
<p>A text representation, validates the text to be a valid e-mail address.</p>
|
||||
<p>Corresponds to <code>django.db.models.fields.EmailField</code></p>
|
||||
<h2 id="regexfield">RegexField</h2>
|
||||
<p>A text representation, that validates the given value matches against a certain regular expression.</p>
|
||||
<p>Uses Django's <code>django.core.validators.RegexValidator</code> for validation.</p>
|
||||
<p>Corresponds to <code>django.forms.fields.RegexField</code></p>
|
||||
<p><strong>Signature:</strong> <code>RegexField(regex, max_length=None, min_length=None)</code></p>
|
||||
<h2 id="datetimefield">DateTimeField</h2>
|
||||
<p>A date and time representation.</p>
|
||||
<p>Corresponds to <code>django.db.models.fields.DateTimeField</code></p>
|
||||
<p>When using <code>ModelSerializer</code> or <code>HyperlinkedModelSerializer</code>, note that any model fields with <code>auto_now=True</code> or <code>auto_now_add=True</code> will use serializer fields that are <code>read_only=True</code> by default.</p>
|
||||
<p>If you want to override this behavior, you'll need to declare the <code>DateTimeField</code> explicitly on the serializer. For example:</p>
|
||||
<pre class="prettyprint lang-py"><code>class CommentSerializer(serializers.ModelSerializer):
|
||||
created = serializers.DateTimeField()
|
||||
|
||||
class Meta:
|
||||
model = Comment
|
||||
</code></pre>
|
||||
<p>Note that by default, datetime representations are determined by the renderer in use, although this can be explicitly overridden as detailed below.</p>
|
||||
<p>In the case of JSON this means the default datetime representation uses the <a href="http://ecma-international.org/ecma-262/5.1/#sec-15.9.1.15">ECMA 262 date time string specification</a>. This is a subset of ISO 8601 which uses millisecond precision, and includes the 'Z' suffix for the UTC timezone, for example: <code>2013-01-29T12:34:56.123Z</code>.</p>
|
||||
<p><strong>Signature:</strong> <code>DateTimeField(format=None, input_formats=None)</code></p>
|
||||
<ul>
|
||||
<li><code>format</code> - A string representing the output format. If not specified, this defaults to <code>None</code>, which indicates that Python <code>datetime</code> objects should be returned by <code>to_native</code>. In this case the datetime encoding will be determined by the renderer. </li>
|
||||
<li><code>input_formats</code> - A list of strings representing the input formats which may be used to parse the date. If not specified, the <code>DATETIME_INPUT_FORMATS</code> setting will be used, which defaults to <code>['iso-8601']</code>.</li>
|
||||
</ul>
|
||||
<p>DateTime format strings may either be <a href="http://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior">Python strftime formats</a> which explicitly specify the format, or the special string <code>'iso-8601'</code>, which indicates that <a href="http://www.w3.org/TR/NOTE-datetime">ISO 8601</a> style datetimes should be used. (eg <code>'2013-01-29T12:34:56.000000Z'</code>)</p>
|
||||
<h2 id="datefield">DateField</h2>
|
||||
<p>A date representation.</p>
|
||||
<p>Corresponds to <code>django.db.models.fields.DateField</code></p>
|
||||
<p><strong>Signature:</strong> <code>DateField(format=None, input_formats=None)</code></p>
|
||||
<ul>
|
||||
<li><code>format</code> - A string representing the output format. If not specified, this defaults to <code>None</code>, which indicates that Python <code>date</code> objects should be returned by <code>to_native</code>. In this case the date encoding will be determined by the renderer.</li>
|
||||
<li><code>input_formats</code> - A list of strings representing the input formats which may be used to parse the date. If not specified, the <code>DATE_INPUT_FORMATS</code> setting will be used, which defaults to <code>['iso-8601']</code>.</li>
|
||||
</ul>
|
||||
<p>Date format strings may either be <a href="http://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior">Python strftime formats</a> which explicitly specify the format, or the special string <code>'iso-8601'</code>, which indicates that <a href="http://www.w3.org/TR/NOTE-datetime">ISO 8601</a> style dates should be used. (eg <code>'2013-01-29'</code>)</p>
|
||||
<h2 id="timefield">TimeField</h2>
|
||||
<p>A time representation.</p>
|
||||
<p>Optionally takes <code>format</code> as parameter to replace the matching pattern.</p>
|
||||
<p>Corresponds to <code>django.db.models.fields.TimeField</code></p>
|
||||
<p><strong>Signature:</strong> <code>TimeField(format=None, input_formats=None)</code></p>
|
||||
<ul>
|
||||
<li><code>format</code> - A string representing the output format. If not specified, this defaults to <code>None</code>, which indicates that Python <code>time</code> objects should be returned by <code>to_native</code>. In this case the time encoding will be determined by the renderer.</li>
|
||||
<li><code>input_formats</code> - A list of strings representing the input formats which may be used to parse the date. If not specified, the <code>TIME_INPUT_FORMATS</code> setting will be used, which defaults to <code>['iso-8601']</code>.</li>
|
||||
</ul>
|
||||
<p>Time format strings may either be <a href="http://docs.python.org/2/library/datetime.html#strftime-and-strptime-behavior">Python strftime formats</a> which explicitly specify the format, or the special string <code>'iso-8601'</code>, which indicates that <a href="http://www.w3.org/TR/NOTE-datetime">ISO 8601</a> style times should be used. (eg <code>'12:34:56.000000'</code>)</p>
|
||||
<h2 id="integerfield">IntegerField</h2>
|
||||
<p>An integer representation.</p>
|
||||
<p>Corresponds to <code>django.db.models.fields.IntegerField</code>, <code>django.db.models.fields.SmallIntegerField</code>, <code>django.db.models.fields.PositiveIntegerField</code> and <code>django.db.models.fields.PositiveSmallIntegerField</code></p>
|
||||
<h2 id="floatfield">FloatField</h2>
|
||||
<p>A floating point representation.</p>
|
||||
<p>Corresponds to <code>django.db.models.fields.FloatField</code>.</p>
|
||||
<h2 id="decimalfield">DecimalField</h2>
|
||||
<p>A decimal representation.</p>
|
||||
<p>Corresponds to <code>django.db.models.fields.DecimalField</code>.</p>
|
||||
<h2 id="filefield">FileField</h2>
|
||||
<p>A file representation. Performs Django's standard FileField validation.</p>
|
||||
<p>Corresponds to <code>django.forms.fields.FileField</code>.</p>
|
||||
<p><strong>Signature:</strong> <code>FileField(max_length=None, allow_empty_file=False)</code></p>
|
||||
<ul>
|
||||
<li>
|
||||
<p><code>max_length</code> designates the maximum length for the file name.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><code>allow_empty_file</code> designates if empty files are allowed.</p>
|
||||
</li>
|
||||
</ul>
|
||||
<h2 id="imagefield">ImageField</h2>
|
||||
<p>An image representation.</p>
|
||||
<p>Corresponds to <code>django.forms.fields.ImageField</code>.</p>
|
||||
<p>Requires the <code>PIL</code> package.</p>
|
||||
<p>Signature and validation is the same as with <code>FileField</code>.</p>
|
||||
<hr />
|
||||
<p><strong>Note:</strong> <code>FileFields</code> and <code>ImageFields</code> are only suitable for use with MultiPartParser, since e.g. json doesn't support file uploads.
|
||||
Django's regular <a href="https://docs.djangoproject.com/en/dev/ref/settings/#std:setting-FILE_UPLOAD_HANDLERS">FILE_UPLOAD_HANDLERS</a> are used for handling uploaded files.</p>
|
||||
<hr />
|
||||
<h1 id="custom-fields">Custom fields</h1>
|
||||
<p>If you want to create a custom field, you'll probably want to override either one or both of the <code>.to_native()</code> and <code>.from_native()</code> methods. These two methods are used to convert between the initial datatype, and a primitive, serializable datatype. Primitive datatypes may be any of a number, string, date/time/datetime or None. They may also be any list or dictionary like object that only contains other primitive objects.</p>
|
||||
<p>The <code>.to_native()</code> method is called to convert the initial datatype into a primitive, serializable datatype. The <code>from_native()</code> method is called to restore a primitive datatype into it's initial representation.</p>
|
||||
<h2 id="examples">Examples</h2>
|
||||
<p>Let's look at an example of serializing a class that represents an RGB color value:</p>
|
||||
<pre class="prettyprint lang-py"><code>class Color(object):
|
||||
"""
|
||||
A color represented in the RGB colorspace.
|
||||
"""
|
||||
def __init__(self, red, green, blue):
|
||||
assert(red >= 0 and green >= 0 and blue >= 0)
|
||||
assert(red < 256 and green < 256 and blue < 256)
|
||||
self.red, self.green, self.blue = red, green, blue
|
||||
|
||||
class ColourField(serializers.WritableField):
|
||||
"""
|
||||
Color objects are serialized into "rgb(#, #, #)" notation.
|
||||
"""
|
||||
def to_native(self, obj):
|
||||
return "rgb(%d, %d, %d)" % (obj.red, obj.green, obj.blue)
|
||||
|
||||
def from_native(self, data):
|
||||
data = data.strip('rgb(').rstrip(')')
|
||||
red, green, blue = [int(col) for col in data.split(',')]
|
||||
return Color(red, green, blue)
|
||||
</code></pre>
|
||||
<p>By default field values are treated as mapping to an attribute on the object. If you need to customize how the field value is accessed and set you need to override <code>.field_to_native()</code> and/or <code>.field_from_native()</code>.</p>
|
||||
<p>As an example, let's create a field that can be used represent the class name of the object being serialized:</p>
|
||||
<pre class="prettyprint lang-py"><code>class ClassNameField(serializers.Field):
|
||||
def field_to_native(self, obj, field_name):
|
||||
"""
|
||||
Serialize the object's class name.
|
||||
"""
|
||||
return obj.__class__
|
||||
</code></pre>
|
||||
</div><!--/span-->
|
||||
</div><!--/row-->
|
||||
</div><!--/.fluid-container-->
|
||||
</div><!--/.body content-->
|
||||
|
||||
<div id="push"></div>
|
||||
</div><!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a></p>
|
||||
</footer>
|
||||
|
||||
<!-- Le javascript
|
||||
================================================== -->
|
||||
<!-- Placed at the end of the document so the pages load faster -->
|
||||
<script src="http://django-rest-framework.org/js/jquery-1.8.1-min.js"></script>
|
||||
<script src="http://django-rest-framework.org/js/prettify-1.0.js"></script>
|
||||
<script src="http://django-rest-framework.org/js/bootstrap-2.1.1-min.js"></script>
|
||||
<script>
|
||||
//$('.side-nav').scrollspy()
|
||||
var shiftWindow = function() { scrollBy(0, -50) };
|
||||
if (location.hash) shiftWindow();
|
||||
window.addEventListener("hashchange", shiftWindow);
|
||||
|
||||
$('.dropdown-menu').on('click touchstart', function(event) {
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
// Dynamically force sidenav to no higher than browser window
|
||||
$('.side-nav').css('max-height', window.innerHeight - 130);
|
||||
|
||||
$(function(){
|
||||
$(window).resize(function(){
|
||||
$('.side-nav').css('max-height', window.innerHeight - 130);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body></html>
|
||||
533
api-guide/filtering.html
Normal file
533
api-guide/filtering.html
Normal file
|
|
@ -0,0 +1,533 @@
|
|||
<!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 - Filtering</title>
|
||||
<link href="http://django-rest-framework.org/img/favicon.ico" rel="icon" type="image/x-icon">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Django, API, REST, Filtering, Generic Filtering, API Guide, Custom generic filtering">
|
||||
<meta name="author" content="Tom Christie">
|
||||
|
||||
<!-- Le styles -->
|
||||
<link href="http://django-rest-framework.org/css/prettify.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/bootstrap.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/bootstrap-responsive.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/default.css" rel="stylesheet">
|
||||
|
||||
<!-- 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]-->
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-18852272-2']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="prettyPrint()" class="filtering-page">
|
||||
|
||||
<div class="wrapper">
|
||||
|
||||
<div class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container-fluid">
|
||||
<a class="repo-link btn btn-primary btn-small" href="https://github.com/tomchristie/django-rest-framework/tree/master">GitHub</a>
|
||||
<a class="repo-link btn btn-inverse btn-small " href="../api-guide/pagination.html">Next <i class="icon-arrow-right icon-white"></i></a>
|
||||
<a class="repo-link btn btn-inverse btn-small " href="../api-guide/throttling.html"><i class="icon-arrow-left icon-white"></i> Previous</a>
|
||||
<a class="repo-link btn btn-inverse btn-small" href="#searchModal" data-toggle="modal"><i class="icon-search icon-white"></i> Search</a>
|
||||
<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>
|
||||
<a class="brand" href="http://django-rest-framework.org">Django REST framework</a>
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav">
|
||||
<li><a href="http://django-rest-framework.org">Home</a></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Tutorial <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/tutorial/quickstart.html">Quickstart</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/1-serialization.html">1 - Serialization</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/2-requests-and-responses.html">2 - Requests and responses</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/3-class-based-views.html">3 - Class based views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/4-authentication-and-permissions.html">4 - Authentication and permissions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/5-relationships-and-hyperlinked-apis.html">5 - Relationships and hyperlinked APIs</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/6-viewsets-and-routers.html">6 - Viewsets and routers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">API Guide <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/api-guide/requests.html">Requests</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/responses.html">Responses</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/views.html">Views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/generic-views.html">Generic views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/viewsets.html">Viewsets</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/routers.html">Routers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/parsers.html">Parsers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/renderers.html">Renderers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/serializers.html">Serializers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/fields.html">Serializer fields</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/relations.html">Serializer relations</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/authentication.html">Authentication</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/permissions.html">Permissions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/throttling.html">Throttling</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/filtering.html">Filtering</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/pagination.html">Pagination</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/content-negotiation.html">Content negotiation</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/format-suffixes.html">Format suffixes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/reverse.html">Returning URLs</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/exceptions.html">Exceptions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/status-codes.html">Status codes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/testing.html">Testing</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/settings.html">Settings</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Topics <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/topics/documenting-your-api.html">Documenting your API</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/ajax-csrf-cors.html">AJAX, CSRF & CORS</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/browser-enhancements.html">Browser enhancements</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/browsable-api.html">The Browsable API</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/rest-hypermedia-hateoas.html">REST, Hypermedia & HATEOAS</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/rest-framework-2-announcement.html">2.0 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/2.2-announcement.html">2.2 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/2.3-announcement.html">2.3 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/release-notes.html">Release Notes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/credits.html">Credits</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="nav pull-right">
|
||||
<!-- TODO
|
||||
<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>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="body-content">
|
||||
<div class="container-fluid">
|
||||
|
||||
<!-- Search Modal -->
|
||||
<div id="searchModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3 id="myModalLabel">Documentation search</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<!-- Custom google search -->
|
||||
<script>
|
||||
(function() {
|
||||
var cx = '015016005043623903336:rxraeohqk6w';
|
||||
var gcse = document.createElement('script');
|
||||
gcse.type = 'text/javascript';
|
||||
gcse.async = true;
|
||||
gcse.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') +
|
||||
'//www.google.com/cse/cse.js?cx=' + cx;
|
||||
var s = document.getElementsByTagName('script')[0];
|
||||
s.parentNode.insertBefore(gcse, s);
|
||||
})();
|
||||
</script>
|
||||
<gcse:search></gcse:search>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row-fluid">
|
||||
|
||||
<div class="span3">
|
||||
<!-- TODO
|
||||
<p style="margin-top: -12px">
|
||||
<a class="btn btn-mini btn-primary" style="width: 60px">« previous</a>
|
||||
<a class="btn btn-mini btn-primary" style="float: right; margin-right: 8px; width: 60px;">next »</a>
|
||||
</p>
|
||||
-->
|
||||
<div id="table-of-contents">
|
||||
<ul class="nav nav-list side-nav well sidebar-nav-fixed">
|
||||
<li class="main"><a href="#filtering">Filtering</a></li>
|
||||
<li><a href="#filtering-against-the-current-user">Filtering against the current user</a></li>
|
||||
<li><a href="#filtering-against-the-url">Filtering against the URL</a></li>
|
||||
<li><a href="#filtering-against-query-parameters">Filtering against query parameters</a></li>
|
||||
<li class="main"><a href="#generic-filtering">Generic Filtering</a></li>
|
||||
<li><a href="#setting-filter-backends">Setting filter backends</a></li>
|
||||
<li><a href="#filtering-and-object-lookups">Filtering and object lookups</a></li>
|
||||
<li><a href="#overriding-the-initial-queryset">Overriding the initial queryset</a></li>
|
||||
<li class="main"><a href="#api-guide">API Guide</a></li>
|
||||
<li><a href="#djangofilterbackend">DjangoFilterBackend</a></li>
|
||||
<li><a href="#searchfilter">SearchFilter</a></li>
|
||||
<li><a href="#orderingfilter">OrderingFilter</a></li>
|
||||
<li><a href="#djangoobjectpermissionsfilter">DjangoObjectPermissionsFilter</a></li>
|
||||
<li class="main"><a href="#custom-generic-filtering">Custom generic filtering</a></li>
|
||||
<li><a href="#example">Example</a></li>
|
||||
|
||||
<div>
|
||||
<hr>
|
||||
|
||||
<p><strong>The team behind REST framework are launching a new API service.</strong></p>
|
||||
|
||||
<p>If you want to be first in line when we start issuing invitations, please sign up here:</p>
|
||||
|
||||
<!-- Begin MailChimp Signup Form -->
|
||||
<link href="//cdn-images.mailchimp.com/embedcode/slim-081711.css" rel="stylesheet" type="text/css">
|
||||
<style type="text/css">
|
||||
#mc_embed_signup{background:#fff; clear:left; font:14px Helvetica,Arial,sans-serif; }
|
||||
/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
|
||||
We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
|
||||
</style>
|
||||
<div id="mc_embed_signup" style="background: rgb(245, 245, 245)">
|
||||
<form action="http://dabapps.us1.list-manage1.com/subscribe/post?u=cf73a9994eb5b8d8d461b5dfb&id=cb6af8e8bd" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>
|
||||
<!-- <label for="mce-EMAIL">Keep me posted!</label>
|
||||
--> <input style="width: 90%" type="email" value="" name="EMAIL" class="email" id="mce-EMAIL" placeholder="email address" required>
|
||||
<div class="clear"><input class="btn btn-success" type="submit" value="Yes, keep me posted!" name="subscribe" id="mc-embedded-subscribe" class="button"></div>
|
||||
</form>
|
||||
</div>
|
||||
</style></div>
|
||||
</ul>
|
||||
|
||||
|
||||
<!--End mc_embed_signup-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="main-content" class="span9">
|
||||
<p><a class="github" href="https://github.com/tomchristie/django-rest-framework/tree/master/rest_framework/filters.py"><span class="label label-info">filters.py</span></a></p>
|
||||
<h1 id="filtering">Filtering</h1>
|
||||
<blockquote>
|
||||
<p>The root QuerySet provided by the Manager describes all objects in the database table. Usually, though, you'll need to select only a subset of the complete set of objects.</p>
|
||||
<p>— <a href="https://docs.djangoproject.com/en/dev/topics/db/queries/#retrieving-specific-objects-with-filters">Django documentation</a></p>
|
||||
</blockquote>
|
||||
<p>The default behavior of REST framework's generic list views is to return the entire queryset for a model manager. Often you will want your API to restrict the items that are returned by the queryset.</p>
|
||||
<p>The simplest way to filter the queryset of any view that subclasses <code>GenericAPIView</code> is to override the <code>.get_queryset()</code> method.</p>
|
||||
<p>Overriding this method allows you to customize the queryset returned by the view in a number of different ways.</p>
|
||||
<h2 id="filtering-against-the-current-user">Filtering against the current user</h2>
|
||||
<p>You might want to filter the queryset to ensure that only results relevant to the currently authenticated user making the request are returned.</p>
|
||||
<p>You can do so by filtering based on the value of <code>request.user</code>.</p>
|
||||
<p>For example:</p>
|
||||
<pre class="prettyprint lang-py"><code>from myapp.models import Purchase
|
||||
from myapp.serializers import PurchaseSerializer
|
||||
from rest_framework import generics
|
||||
|
||||
class PurchaseList(generics.ListAPIView)
|
||||
serializer_class = PurchaseSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
"""
|
||||
This view should return a list of all the purchases
|
||||
for the currently authenticated user.
|
||||
"""
|
||||
user = self.request.user
|
||||
return Purchase.objects.filter(purchaser=user)
|
||||
</code></pre>
|
||||
<h2 id="filtering-against-the-url">Filtering against the URL</h2>
|
||||
<p>Another style of filtering might involve restricting the queryset based on some part of the URL. </p>
|
||||
<p>For example if your URL config contained an entry like this:</p>
|
||||
<pre class="prettyprint lang-py"><code>url('^purchases/(?P<username>.+)/$', PurchaseList.as_view()),
|
||||
</code></pre>
|
||||
<p>You could then write a view that returned a purchase queryset filtered by the username portion of the URL:</p>
|
||||
<pre class="prettyprint lang-py"><code>class PurchaseList(generics.ListAPIView)
|
||||
serializer_class = PurchaseSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
"""
|
||||
This view should return a list of all the purchases for
|
||||
the user as determined by the username portion of the URL.
|
||||
"""
|
||||
username = self.kwargs['username']
|
||||
return Purchase.objects.filter(purchaser__username=username)
|
||||
</code></pre>
|
||||
<h2 id="filtering-against-query-parameters">Filtering against query parameters</h2>
|
||||
<p>A final example of filtering the initial queryset would be to determine the initial queryset based on query parameters in the url.</p>
|
||||
<p>We can override <code>.get_queryset()</code> to deal with URLs such as <code>http://example.com/api/purchases?username=denvercoder9</code>, and filter the queryset only if the <code>username</code> parameter is included in the URL:</p>
|
||||
<pre class="prettyprint lang-py"><code>class PurchaseList(generics.ListAPIView)
|
||||
serializer_class = PurchaseSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
"""
|
||||
Optionally restricts the returned purchases to a given user,
|
||||
by filtering against a `username` query parameter in the URL.
|
||||
"""
|
||||
queryset = Purchase.objects.all()
|
||||
username = self.request.QUERY_PARAMS.get('username', None)
|
||||
if username is not None:
|
||||
queryset = queryset.filter(purchaser__username=username)
|
||||
return queryset
|
||||
</code></pre>
|
||||
<hr />
|
||||
<h1 id="generic-filtering">Generic Filtering</h1>
|
||||
<p>As well as being able to override the default queryset, REST framework also includes support for generic filtering backends that allow you to easily construct complex searches and filters.</p>
|
||||
<h2 id="setting-filter-backends">Setting filter backends</h2>
|
||||
<p>The default filter backends may be set globally, using the <code>DEFAULT_FILTER_BACKENDS</code> setting. For example.</p>
|
||||
<pre class="prettyprint lang-py"><code>REST_FRAMEWORK = {
|
||||
'DEFAULT_FILTER_BACKENDS': ('rest_framework.filters.DjangoFilterBackend',)
|
||||
}
|
||||
</code></pre>
|
||||
<p>You can also set the filter backends on a per-view, or per-viewset basis,
|
||||
using the <code>GenericAPIView</code> class based views.</p>
|
||||
<pre class="prettyprint lang-py"><code>from django.contrib.auth.models import User
|
||||
from myapp.serializers import UserSerializer
|
||||
from rest_framework import filters
|
||||
from rest_framework import generics
|
||||
|
||||
class UserListView(generics.ListAPIView):
|
||||
queryset = User.objects.all()
|
||||
serializer = UserSerializer
|
||||
filter_backends = (filters.DjangoFilterBackend,)
|
||||
</code></pre>
|
||||
<h2 id="filtering-and-object-lookups">Filtering and object lookups</h2>
|
||||
<p>Note that if a filter backend is configured for a view, then as well as being used to filter list views, it will also be used to filter the querysets used for returning a single object.</p>
|
||||
<p>For instance, given the previous example, and a product with an id of <code>4675</code>, the following URL would either return the corresponding object, or return a 404 response, depending on if the filtering conditions were met by the given product instance:</p>
|
||||
<pre class="prettyprint lang-py"><code>http://example.com/api/products/4675/?category=clothing&max_price=10.00
|
||||
</code></pre>
|
||||
<h2 id="overriding-the-initial-queryset">Overriding the initial queryset</h2>
|
||||
<p>Note that you can use both an overridden <code>.get_queryset()</code> and generic filtering together, and everything will work as expected. For example, if <code>Product</code> had a many-to-many relationship with <code>User</code>, named <code>purchase</code>, you might want to write a view like this:</p>
|
||||
<pre class="prettyprint lang-py"><code>class PurchasedProductsList(generics.ListAPIView):
|
||||
"""
|
||||
Return a list of all the products that the authenticated
|
||||
user has ever purchased, with optional filtering.
|
||||
"""
|
||||
model = Product
|
||||
serializer_class = ProductSerializer
|
||||
filter_class = ProductFilter
|
||||
|
||||
def get_queryset(self):
|
||||
user = self.request.user
|
||||
return user.purchase_set.all()
|
||||
</code></pre>
|
||||
<hr />
|
||||
<h1 id="api-guide">API Guide</h1>
|
||||
<h2 id="djangofilterbackend">DjangoFilterBackend</h2>
|
||||
<p>The <code>DjangoFilterBackend</code> class supports highly customizable field filtering, using the <a href="https://github.com/alex/django-filter">django-filter package</a>. </p>
|
||||
<p>To use REST framework's <code>DjangoFilterBackend</code>, first install <code>django-filter</code>.</p>
|
||||
<pre class="prettyprint lang-py"><code>pip install django-filter
|
||||
</code></pre>
|
||||
<h4 id="specifying-filter-fields">Specifying filter fields</h4>
|
||||
<p>If all you need is simple equality-based filtering, you can set a <code>filter_fields</code> attribute on the view, or viewset, listing the set of fields you wish to filter against.</p>
|
||||
<pre class="prettyprint lang-py"><code>class ProductList(generics.ListAPIView):
|
||||
queryset = Product.objects.all()
|
||||
serializer_class = ProductSerializer
|
||||
filter_fields = ('category', 'in_stock')
|
||||
</code></pre>
|
||||
<p>This will automatically create a <code>FilterSet</code> class for the given fields, and will allow you to make requests such as:</p>
|
||||
<pre class="prettyprint lang-py"><code>http://example.com/api/products?category=clothing&in_stock=True
|
||||
</code></pre>
|
||||
<h4 id="specifying-a-filterset">Specifying a FilterSet</h4>
|
||||
<p>For more advanced filtering requirements you can specify a <code>FilterSet</code> class that should be used by the view. For example:</p>
|
||||
<pre class="prettyprint lang-py"><code>import django_filters
|
||||
from myapp.models import Product
|
||||
from myapp.serializers import ProductSerializer
|
||||
from rest_framework import generics
|
||||
|
||||
class ProductFilter(django_filters.FilterSet):
|
||||
min_price = django_filters.NumberFilter(name="price", lookup_type='gte')
|
||||
max_price = django_filters.NumberFilter(name="price", lookup_type='lte')
|
||||
class Meta:
|
||||
model = Product
|
||||
fields = ['category', 'in_stock', 'min_price', 'max_price']
|
||||
|
||||
class ProductList(generics.ListAPIView):
|
||||
queryset = Product.objects.all()
|
||||
serializer_class = ProductSerializer
|
||||
filter_class = ProductFilter
|
||||
</code></pre>
|
||||
<p>Which will allow you to make requests such as:</p>
|
||||
<pre class="prettyprint lang-py"><code>http://example.com/api/products?category=clothing&max_price=10.00
|
||||
</code></pre>
|
||||
<p>You can also span relationships using <code>django-filter</code>, let's assume that each
|
||||
product has foreign key to <code>Manufacturer</code> model, so we create filter that
|
||||
filters using <code>Manufacturer</code> name. For example:</p>
|
||||
<pre class="prettyprint lang-py"><code>import django_filters
|
||||
from myapp.models import Product
|
||||
from myapp.serializers import ProductSerializer
|
||||
from rest_framework import generics
|
||||
|
||||
class ProductFilter(django_filters.FilterSet):
|
||||
class Meta:
|
||||
model = Product
|
||||
fields = ['category', 'in_stock', 'manufacturer__name`]
|
||||
</code></pre>
|
||||
<p>This enables us to make queries like:</p>
|
||||
<pre class="prettyprint lang-py"><code>http://example.com/api/products?manufacturer__name=foo
|
||||
</code></pre>
|
||||
<p>This is nice, but it shows underlying model structure in REST API, which may
|
||||
be undesired, but you can use:</p>
|
||||
<pre class="prettyprint lang-py"><code>import django_filters
|
||||
from myapp.models import Product
|
||||
from myapp.serializers import ProductSerializer
|
||||
from rest_framework import generics
|
||||
|
||||
class ProductFilter(django_filters.FilterSet):
|
||||
|
||||
manufacturer = django_filters.CharFilter(name="manufacturer__name")
|
||||
|
||||
class Meta:
|
||||
model = Product
|
||||
fields = ['category', 'in_stock', 'manufacturer`]
|
||||
</code></pre>
|
||||
<p>And now you can execute:</p>
|
||||
<pre class="prettyprint lang-py"><code>http://example.com/api/products?manufacturer=foo
|
||||
</code></pre>
|
||||
<p>For more details on using filter sets see the <a href="https://django-filter.readthedocs.org/en/latest/index.html">django-filter documentation</a>.</p>
|
||||
<hr />
|
||||
<p><strong>Hints & Tips</strong></p>
|
||||
<ul>
|
||||
<li>By default filtering is not enabled. If you want to use <code>DjangoFilterBackend</code> remember to make sure it is installed by using the <code>'DEFAULT_FILTER_BACKENDS'</code> setting.</li>
|
||||
<li>When using boolean fields, you should use the values <code>True</code> and <code>False</code> in the URL query parameters, rather than <code>0</code>, <code>1</code>, <code>true</code> or <code>false</code>. (The allowed boolean values are currently hardwired in Django's <a href="https://github.com/django/django/blob/master/django/forms/widgets.py">NullBooleanSelect implementation</a>.) </li>
|
||||
<li><code>django-filter</code> supports filtering across relationships, using Django's double-underscore syntax.</li>
|
||||
<li>For Django 1.3 support, make sure to install <code>django-filter</code> version 0.5.4, as later versions drop support for 1.3.</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h2 id="searchfilter">SearchFilter</h2>
|
||||
<p>The <code>SearchFilter</code> class supports simple single query parameter based searching, and is based on the <a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.search_fields">Django admin's search functionality</a>.</p>
|
||||
<p>The <code>SearchFilter</code> class will only be applied if the view has a <code>search_fields</code> attribute set. The <code>search_fields</code> attribute should be a list of names of text type fields on the model, such as <code>CharField</code> or <code>TextField</code>.</p>
|
||||
<pre class="prettyprint lang-py"><code>class UserListView(generics.ListAPIView):
|
||||
queryset = User.objects.all()
|
||||
serializer = UserSerializer
|
||||
filter_backends = (filters.SearchFilter,)
|
||||
search_fields = ('username', 'email')
|
||||
</code></pre>
|
||||
<p>This will allow the client to filter the items in the list by making queries such as:</p>
|
||||
<pre class="prettyprint lang-py"><code>http://example.com/api/users?search=russell
|
||||
</code></pre>
|
||||
<p>You can also perform a related lookup on a ForeignKey or ManyToManyField with the lookup API double-underscore notation:</p>
|
||||
<pre class="prettyprint lang-py"><code>search_fields = ('username', 'email', 'profile__profession')
|
||||
</code></pre>
|
||||
<p>By default, searches will use case-insensitive partial matches. The search parameter may contain multiple search terms, which should be whitespace and/or comma separated. If multiple search terms are used then objects will be returned in the list only if all the provided terms are matched.</p>
|
||||
<p>The search behavior may be restricted by prepending various characters to the <code>search_fields</code>.</p>
|
||||
<ul>
|
||||
<li>'^' Starts-with search.</li>
|
||||
<li>'=' Exact matches.</li>
|
||||
<li>'@' Full-text search. (Currently only supported Django's MySQL backend.)</li>
|
||||
</ul>
|
||||
<p>For example:</p>
|
||||
<pre class="prettyprint lang-py"><code>search_fields = ('=username', '=email')
|
||||
</code></pre>
|
||||
<p>For more details, see the <a href="https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.search_fields">Django documentation</a>.</p>
|
||||
<hr />
|
||||
<h2 id="orderingfilter">OrderingFilter</h2>
|
||||
<p>The <code>OrderingFilter</code> class supports simple query parameter controlled ordering of results. To specify the result order, set a query parameter named <code>'ordering'</code> to the required field name. For example:</p>
|
||||
<pre class="prettyprint lang-py"><code>http://example.com/api/users?ordering=username
|
||||
</code></pre>
|
||||
<p>The client may also specify reverse orderings by prefixing the field name with '-', like so:</p>
|
||||
<pre class="prettyprint lang-py"><code>http://example.com/api/users?ordering=-username
|
||||
</code></pre>
|
||||
<p>Multiple orderings may also be specified:</p>
|
||||
<pre class="prettyprint lang-py"><code>http://example.com/api/users?ordering=account,username
|
||||
</code></pre>
|
||||
<p>If an <code>ordering</code> attribute is set on the view, this will be used as the default ordering.</p>
|
||||
<p>Typically you'd instead control this by setting <code>order_by</code> on the initial queryset, but using the <code>ordering</code> parameter on the view allows you to specify the ordering in a way that it can then be passed automatically as context to a rendered template. This makes it possible to automatically render column headers differently if they are being used to order the results.</p>
|
||||
<pre class="prettyprint lang-py"><code>class UserListView(generics.ListAPIView):
|
||||
queryset = User.objects.all()
|
||||
serializer = UserSerializer
|
||||
filter_backends = (filters.OrderingFilter,)
|
||||
ordering = ('username',)
|
||||
</code></pre>
|
||||
<p>The <code>ordering</code> attribute may be either a string or a list/tuple of strings.</p>
|
||||
<hr />
|
||||
<h2 id="djangoobjectpermissionsfilter">DjangoObjectPermissionsFilter</h2>
|
||||
<p>The <code>DjangoObjectPermissionsFilter</code> is intended to be used together with the <a href="http://pythonhosted.org/django-guardian/"><code>django-guardian</code></a> package, with custom <code>'view'</code> permissions added. The filter will ensure that querysets only returns objects for which the user has the appropriate view permission.</p>
|
||||
<p>This filter class must be used with views that provide either a <code>queryset</code> or a <code>model</code> attribute.</p>
|
||||
<p>If you're using <code>DjangoObjectPermissionsFilter</code>, you'll probably also want to add an appropriate object permissions class, to ensure that users can only operate on instances if they have the appropriate object permissions. The easiest way to do this is to subclass <code>DjangoObjectPermissions</code> and add <code>'view'</code> permissions to the <code>perms_map</code> attribute.</p>
|
||||
<p>A complete example using both <code>DjangoObjectPermissionsFilter</code> and <code>DjangoObjectPermissions</code> might look something like this.</p>
|
||||
<p><strong>permissions.py</strong>:</p>
|
||||
<pre class="prettyprint lang-py"><code>class CustomObjectPermissions(permissions.DjangoObjectPermissions):
|
||||
"""
|
||||
Similar to `DjangoObjectPermissions`, but adding 'view' permissions.
|
||||
"""
|
||||
perms_map = {
|
||||
'GET': ['%(app_label)s.view_%(model_name)s'],
|
||||
'OPTIONS': ['%(app_label)s.view_%(model_name)s'],
|
||||
'HEAD': ['%(app_label)s.view_%(model_name)s'],
|
||||
'POST': ['%(app_label)s.add_%(model_name)s'],
|
||||
'PUT': ['%(app_label)s.change_%(model_name)s'],
|
||||
'PATCH': ['%(app_label)s.change_%(model_name)s'],
|
||||
'DELETE': ['%(app_label)s.delete_%(model_name)s'],
|
||||
}
|
||||
</code></pre>
|
||||
<p><strong>views.py</strong>:</p>
|
||||
<pre class="prettyprint lang-py"><code>class EventViewSet(viewsets.ModelViewSet):
|
||||
"""
|
||||
Viewset that only lists events if user has 'view' permissions, and only
|
||||
allows operations on individual events if user has appropriate 'view', 'add',
|
||||
'change' or 'delete' permissions.
|
||||
"""
|
||||
queryset = Event.objects.all()
|
||||
serializer = EventSerializer
|
||||
filter_backends = (filters.DjangoObjectPermissionsFilter,)
|
||||
permission_classes = (myapp.permissions.CustomObjectPermissions,)
|
||||
</code></pre>
|
||||
<p>For more information on adding <code>'view'</code> permissions for models, see the <a href="http://pythonhosted.org/django-guardian/userguide/assign.html">relevant section</a> of the <code>django-guardian</code> documentation, and <a href="http://blog.nyaruka.com/adding-a-view-permission-to-django-models">this blogpost</a>.</p>
|
||||
<hr />
|
||||
<h1 id="custom-generic-filtering">Custom generic filtering</h1>
|
||||
<p>You can also provide your own generic filtering backend, or write an installable app for other developers to use.</p>
|
||||
<p>To do so override <code>BaseFilterBackend</code>, and override the <code>.filter_queryset(self, request, queryset, view)</code> method. The method should return a new, filtered queryset.</p>
|
||||
<p>As well as allowing clients to perform searches and filtering, generic filter backends can be useful for restricting which objects should be visible to any given request or user.</p>
|
||||
<h2 id="example">Example</h2>
|
||||
<p>For example, you might need to restrict users to only being able to see objects they created.</p>
|
||||
<pre class="prettyprint lang-py"><code>class IsOwnerFilterBackend(filters.BaseFilterBackend):
|
||||
"""
|
||||
Filter that only allows users to see their own objects.
|
||||
"""
|
||||
def filter_queryset(self, request, queryset, view):
|
||||
return queryset.filter(owner=request.user)
|
||||
</code></pre>
|
||||
<p>We could achieve the same behavior by overriding <code>get_queryset()</code> on the views, but using a filter backend allows you to more easily add this restriction to multiple views, or to apply it across the entire API.</p>
|
||||
</div><!--/span-->
|
||||
</div><!--/row-->
|
||||
</div><!--/.fluid-container-->
|
||||
</div><!--/.body content-->
|
||||
|
||||
<div id="push"></div>
|
||||
</div><!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a></p>
|
||||
</footer>
|
||||
|
||||
<!-- Le javascript
|
||||
================================================== -->
|
||||
<!-- Placed at the end of the document so the pages load faster -->
|
||||
<script src="http://django-rest-framework.org/js/jquery-1.8.1-min.js"></script>
|
||||
<script src="http://django-rest-framework.org/js/prettify-1.0.js"></script>
|
||||
<script src="http://django-rest-framework.org/js/bootstrap-2.1.1-min.js"></script>
|
||||
<script>
|
||||
//$('.side-nav').scrollspy()
|
||||
var shiftWindow = function() { scrollBy(0, -50) };
|
||||
if (location.hash) shiftWindow();
|
||||
window.addEventListener("hashchange", shiftWindow);
|
||||
|
||||
$('.dropdown-menu').on('click touchstart', function(event) {
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
// Dynamically force sidenav to no higher than browser window
|
||||
$('.side-nav').css('max-height', window.innerHeight - 130);
|
||||
|
||||
$(function(){
|
||||
$(window).resize(function(){
|
||||
$('.side-nav').css('max-height', window.innerHeight - 130);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body></html>
|
||||
290
api-guide/format-suffixes.html
Normal file
290
api-guide/format-suffixes.html
Normal file
|
|
@ -0,0 +1,290 @@
|
|||
<!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 - Format suffixes</title>
|
||||
<link href="http://django-rest-framework.org/img/favicon.ico" rel="icon" type="image/x-icon">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Django, API, REST, Format suffixes">
|
||||
<meta name="author" content="Tom Christie">
|
||||
|
||||
<!-- Le styles -->
|
||||
<link href="http://django-rest-framework.org/css/prettify.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/bootstrap.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/bootstrap-responsive.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/default.css" rel="stylesheet">
|
||||
|
||||
<!-- 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]-->
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-18852272-2']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="prettyPrint()" class="format-suffixes-page">
|
||||
|
||||
<div class="wrapper">
|
||||
|
||||
<div class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container-fluid">
|
||||
<a class="repo-link btn btn-primary btn-small" href="https://github.com/tomchristie/django-rest-framework/tree/master">GitHub</a>
|
||||
<a class="repo-link btn btn-inverse btn-small " href="../api-guide/reverse.html">Next <i class="icon-arrow-right icon-white"></i></a>
|
||||
<a class="repo-link btn btn-inverse btn-small " href="../api-guide/content-negotiation.html"><i class="icon-arrow-left icon-white"></i> Previous</a>
|
||||
<a class="repo-link btn btn-inverse btn-small" href="#searchModal" data-toggle="modal"><i class="icon-search icon-white"></i> Search</a>
|
||||
<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>
|
||||
<a class="brand" href="http://django-rest-framework.org">Django REST framework</a>
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav">
|
||||
<li><a href="http://django-rest-framework.org">Home</a></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Tutorial <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/tutorial/quickstart.html">Quickstart</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/1-serialization.html">1 - Serialization</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/2-requests-and-responses.html">2 - Requests and responses</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/3-class-based-views.html">3 - Class based views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/4-authentication-and-permissions.html">4 - Authentication and permissions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/5-relationships-and-hyperlinked-apis.html">5 - Relationships and hyperlinked APIs</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/6-viewsets-and-routers.html">6 - Viewsets and routers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">API Guide <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/api-guide/requests.html">Requests</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/responses.html">Responses</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/views.html">Views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/generic-views.html">Generic views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/viewsets.html">Viewsets</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/routers.html">Routers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/parsers.html">Parsers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/renderers.html">Renderers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/serializers.html">Serializers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/fields.html">Serializer fields</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/relations.html">Serializer relations</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/authentication.html">Authentication</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/permissions.html">Permissions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/throttling.html">Throttling</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/filtering.html">Filtering</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/pagination.html">Pagination</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/content-negotiation.html">Content negotiation</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/format-suffixes.html">Format suffixes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/reverse.html">Returning URLs</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/exceptions.html">Exceptions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/status-codes.html">Status codes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/testing.html">Testing</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/settings.html">Settings</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Topics <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/topics/documenting-your-api.html">Documenting your API</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/ajax-csrf-cors.html">AJAX, CSRF & CORS</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/browser-enhancements.html">Browser enhancements</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/browsable-api.html">The Browsable API</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/rest-hypermedia-hateoas.html">REST, Hypermedia & HATEOAS</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/rest-framework-2-announcement.html">2.0 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/2.2-announcement.html">2.2 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/2.3-announcement.html">2.3 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/release-notes.html">Release Notes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/credits.html">Credits</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="nav pull-right">
|
||||
<!-- TODO
|
||||
<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>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="body-content">
|
||||
<div class="container-fluid">
|
||||
|
||||
<!-- Search Modal -->
|
||||
<div id="searchModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3 id="myModalLabel">Documentation search</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<!-- Custom google search -->
|
||||
<script>
|
||||
(function() {
|
||||
var cx = '015016005043623903336:rxraeohqk6w';
|
||||
var gcse = document.createElement('script');
|
||||
gcse.type = 'text/javascript';
|
||||
gcse.async = true;
|
||||
gcse.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') +
|
||||
'//www.google.com/cse/cse.js?cx=' + cx;
|
||||
var s = document.getElementsByTagName('script')[0];
|
||||
s.parentNode.insertBefore(gcse, s);
|
||||
})();
|
||||
</script>
|
||||
<gcse:search></gcse:search>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row-fluid">
|
||||
|
||||
<div class="span3">
|
||||
<!-- TODO
|
||||
<p style="margin-top: -12px">
|
||||
<a class="btn btn-mini btn-primary" style="width: 60px">« previous</a>
|
||||
<a class="btn btn-mini btn-primary" style="float: right; margin-right: 8px; width: 60px;">next »</a>
|
||||
</p>
|
||||
-->
|
||||
<div id="table-of-contents">
|
||||
<ul class="nav nav-list side-nav well sidebar-nav-fixed">
|
||||
<li class="main"><a href="#format-suffixes">Format suffixes</a></li>
|
||||
<li><a href="#format_suffix_patterns">format_suffix_patterns</a></li>
|
||||
<li><a href="#accept-headers-vs-format-suffixes">Accept headers vs. format suffixes</a></li>
|
||||
|
||||
<div>
|
||||
<hr>
|
||||
|
||||
<p><strong>The team behind REST framework are launching a new API service.</strong></p>
|
||||
|
||||
<p>If you want to be first in line when we start issuing invitations, please sign up here:</p>
|
||||
|
||||
<!-- Begin MailChimp Signup Form -->
|
||||
<link href="//cdn-images.mailchimp.com/embedcode/slim-081711.css" rel="stylesheet" type="text/css">
|
||||
<style type="text/css">
|
||||
#mc_embed_signup{background:#fff; clear:left; font:14px Helvetica,Arial,sans-serif; }
|
||||
/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
|
||||
We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
|
||||
</style>
|
||||
<div id="mc_embed_signup" style="background: rgb(245, 245, 245)">
|
||||
<form action="http://dabapps.us1.list-manage1.com/subscribe/post?u=cf73a9994eb5b8d8d461b5dfb&id=cb6af8e8bd" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>
|
||||
<!-- <label for="mce-EMAIL">Keep me posted!</label>
|
||||
--> <input style="width: 90%" type="email" value="" name="EMAIL" class="email" id="mce-EMAIL" placeholder="email address" required>
|
||||
<div class="clear"><input class="btn btn-success" type="submit" value="Yes, keep me posted!" name="subscribe" id="mc-embedded-subscribe" class="button"></div>
|
||||
</form>
|
||||
</div>
|
||||
</style></div>
|
||||
</ul>
|
||||
|
||||
|
||||
<!--End mc_embed_signup-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="main-content" class="span9">
|
||||
<p><a class="github" href="https://github.com/tomchristie/django-rest-framework/tree/master/rest_framework/urlpatterns.py"><span class="label label-info">urlpatterns.py</span></a></p>
|
||||
<h1 id="format-suffixes">Format suffixes</h1>
|
||||
<blockquote>
|
||||
<p>Section 6.2.1 does not say that content negotiation should be
|
||||
used all the time.</p>
|
||||
<p>— Roy Fielding, <a href="http://tech.groups.yahoo.com/group/rest-discuss/message/5857">REST discuss mailing list</a></p>
|
||||
</blockquote>
|
||||
<p>A common pattern for Web APIs is to use filename extensions on URLs to provide an endpoint for a given media type. For example, 'http://example.com/api/users.json' to serve a JSON representation. </p>
|
||||
<p>Adding format-suffix patterns to each individual entry in the URLconf for your API is error-prone and non-DRY, so REST framework provides a shortcut to adding these patterns to your URLConf.</p>
|
||||
<h2 id="format_suffix_patterns">format_suffix_patterns</h2>
|
||||
<p><strong>Signature</strong>: format_suffix_patterns(urlpatterns, suffix_required=False, allowed=None)</p>
|
||||
<p>Returns a URL pattern list which includes format suffix patterns appended to each of the URL patterns provided.</p>
|
||||
<p>Arguments:</p>
|
||||
<ul>
|
||||
<li><strong>urlpatterns</strong>: Required. A URL pattern list.</li>
|
||||
<li><strong>suffix_required</strong>: Optional. A boolean indicating if suffixes in the URLs should be optional or mandatory. Defaults to <code>False</code>, meaning that suffixes are optional by default.</li>
|
||||
<li><strong>allowed</strong>: Optional. A list or tuple of valid format suffixes. If not provided, a wildcard format suffix pattern will be used. </li>
|
||||
</ul>
|
||||
<p>Example:</p>
|
||||
<pre class="prettyprint lang-py"><code>from rest_framework.urlpatterns import format_suffix_patterns
|
||||
|
||||
urlpatterns = patterns('blog.views',
|
||||
url(r'^/$', 'api_root'),
|
||||
url(r'^comments/$', 'comment_list'),
|
||||
url(r'^comments/(?P<pk>[0-9]+)/$', 'comment_detail')
|
||||
)
|
||||
|
||||
urlpatterns = format_suffix_patterns(urlpatterns, allowed=['json', 'html'])
|
||||
</code></pre>
|
||||
<p>When using <code>format_suffix_patterns</code>, you must make sure to add the <code>'format'</code> keyword argument to the corresponding views. For example:</p>
|
||||
<pre class="prettyprint lang-py"><code>@api_view(('GET', 'POST'))
|
||||
def comment_list(request, format=None):
|
||||
# do stuff...
|
||||
</code></pre>
|
||||
<p>Or with class based views:</p>
|
||||
<pre class="prettyprint lang-py"><code>class CommentList(APIView):
|
||||
def get(self, request, format=None):
|
||||
# do stuff...
|
||||
|
||||
def post(self, request, format=None):
|
||||
# do stuff...
|
||||
</code></pre>
|
||||
<p>The name of the kwarg used may be modified by using the <code>FORMAT_SUFFIX_KWARG</code> setting.</p>
|
||||
<p>Also note that <code>format_suffix_patterns</code> does not support descending into <code>include</code> URL patterns.</p>
|
||||
<hr />
|
||||
<h2 id="accept-headers-vs-format-suffixes">Accept headers vs. format suffixes</h2>
|
||||
<p>There seems to be a view among some of the Web community that filename extensions are not a RESTful pattern, and that <code>HTTP Accept</code> headers should always be used instead.</p>
|
||||
<p>It is actually a misconception. For example, take the following quote from Roy Fielding discussing the relative merits of query parameter media-type indicators vs. file extension media-type indicators: </p>
|
||||
<p>“That's why I always prefer extensions. Neither choice has anything to do with REST.” — Roy Fielding, <a href="http://tech.groups.yahoo.com/group/rest-discuss/message/14844">REST discuss mailing list</a></p>
|
||||
<p>The quote does not mention Accept headers, but it does make it clear that format suffixes should be considered an acceptable pattern.</p>
|
||||
</div><!--/span-->
|
||||
</div><!--/row-->
|
||||
</div><!--/.fluid-container-->
|
||||
</div><!--/.body content-->
|
||||
|
||||
<div id="push"></div>
|
||||
</div><!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a></p>
|
||||
</footer>
|
||||
|
||||
<!-- Le javascript
|
||||
================================================== -->
|
||||
<!-- Placed at the end of the document so the pages load faster -->
|
||||
<script src="http://django-rest-framework.org/js/jquery-1.8.1-min.js"></script>
|
||||
<script src="http://django-rest-framework.org/js/prettify-1.0.js"></script>
|
||||
<script src="http://django-rest-framework.org/js/bootstrap-2.1.1-min.js"></script>
|
||||
<script>
|
||||
//$('.side-nav').scrollspy()
|
||||
var shiftWindow = function() { scrollBy(0, -50) };
|
||||
if (location.hash) shiftWindow();
|
||||
window.addEventListener("hashchange", shiftWindow);
|
||||
|
||||
$('.dropdown-menu').on('click touchstart', function(event) {
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
// Dynamically force sidenav to no higher than browser window
|
||||
$('.side-nav').css('max-height', window.innerHeight - 130);
|
||||
|
||||
$(function(){
|
||||
$(window).resize(function(){
|
||||
$('.side-nav').css('max-height', window.innerHeight - 130);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body></html>
|
||||
506
api-guide/generic-views.html
Normal file
506
api-guide/generic-views.html
Normal file
|
|
@ -0,0 +1,506 @@
|
|||
<!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 - Generic views</title>
|
||||
<link href="http://django-rest-framework.org/img/favicon.ico" rel="icon" type="image/x-icon">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Django, API, REST, Generic views, API Reference, Mixins, Concrete View Classes, Customizing the generic views">
|
||||
<meta name="author" content="Tom Christie">
|
||||
|
||||
<!-- Le styles -->
|
||||
<link href="http://django-rest-framework.org/css/prettify.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/bootstrap.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/bootstrap-responsive.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/default.css" rel="stylesheet">
|
||||
|
||||
<!-- 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]-->
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-18852272-2']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="prettyPrint()" class="generic-views-page">
|
||||
|
||||
<div class="wrapper">
|
||||
|
||||
<div class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container-fluid">
|
||||
<a class="repo-link btn btn-primary btn-small" href="https://github.com/tomchristie/django-rest-framework/tree/master">GitHub</a>
|
||||
<a class="repo-link btn btn-inverse btn-small " href="../api-guide/viewsets.html">Next <i class="icon-arrow-right icon-white"></i></a>
|
||||
<a class="repo-link btn btn-inverse btn-small " href="../api-guide/views.html"><i class="icon-arrow-left icon-white"></i> Previous</a>
|
||||
<a class="repo-link btn btn-inverse btn-small" href="#searchModal" data-toggle="modal"><i class="icon-search icon-white"></i> Search</a>
|
||||
<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>
|
||||
<a class="brand" href="http://django-rest-framework.org">Django REST framework</a>
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav">
|
||||
<li><a href="http://django-rest-framework.org">Home</a></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Tutorial <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/tutorial/quickstart.html">Quickstart</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/1-serialization.html">1 - Serialization</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/2-requests-and-responses.html">2 - Requests and responses</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/3-class-based-views.html">3 - Class based views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/4-authentication-and-permissions.html">4 - Authentication and permissions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/5-relationships-and-hyperlinked-apis.html">5 - Relationships and hyperlinked APIs</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/6-viewsets-and-routers.html">6 - Viewsets and routers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">API Guide <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/api-guide/requests.html">Requests</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/responses.html">Responses</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/views.html">Views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/generic-views.html">Generic views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/viewsets.html">Viewsets</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/routers.html">Routers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/parsers.html">Parsers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/renderers.html">Renderers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/serializers.html">Serializers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/fields.html">Serializer fields</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/relations.html">Serializer relations</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/authentication.html">Authentication</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/permissions.html">Permissions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/throttling.html">Throttling</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/filtering.html">Filtering</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/pagination.html">Pagination</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/content-negotiation.html">Content negotiation</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/format-suffixes.html">Format suffixes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/reverse.html">Returning URLs</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/exceptions.html">Exceptions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/status-codes.html">Status codes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/testing.html">Testing</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/settings.html">Settings</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Topics <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/topics/documenting-your-api.html">Documenting your API</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/ajax-csrf-cors.html">AJAX, CSRF & CORS</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/browser-enhancements.html">Browser enhancements</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/browsable-api.html">The Browsable API</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/rest-hypermedia-hateoas.html">REST, Hypermedia & HATEOAS</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/rest-framework-2-announcement.html">2.0 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/2.2-announcement.html">2.2 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/2.3-announcement.html">2.3 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/release-notes.html">Release Notes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/credits.html">Credits</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="nav pull-right">
|
||||
<!-- TODO
|
||||
<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>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="body-content">
|
||||
<div class="container-fluid">
|
||||
|
||||
<!-- Search Modal -->
|
||||
<div id="searchModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3 id="myModalLabel">Documentation search</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<!-- Custom google search -->
|
||||
<script>
|
||||
(function() {
|
||||
var cx = '015016005043623903336:rxraeohqk6w';
|
||||
var gcse = document.createElement('script');
|
||||
gcse.type = 'text/javascript';
|
||||
gcse.async = true;
|
||||
gcse.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') +
|
||||
'//www.google.com/cse/cse.js?cx=' + cx;
|
||||
var s = document.getElementsByTagName('script')[0];
|
||||
s.parentNode.insertBefore(gcse, s);
|
||||
})();
|
||||
</script>
|
||||
<gcse:search></gcse:search>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row-fluid">
|
||||
|
||||
<div class="span3">
|
||||
<!-- TODO
|
||||
<p style="margin-top: -12px">
|
||||
<a class="btn btn-mini btn-primary" style="width: 60px">« previous</a>
|
||||
<a class="btn btn-mini btn-primary" style="float: right; margin-right: 8px; width: 60px;">next »</a>
|
||||
</p>
|
||||
-->
|
||||
<div id="table-of-contents">
|
||||
<ul class="nav nav-list side-nav well sidebar-nav-fixed">
|
||||
<li class="main"><a href="#generic-views">Generic views</a></li>
|
||||
<li><a href="#examples">Examples</a></li>
|
||||
<li class="main"><a href="#api-reference">API Reference</a></li>
|
||||
<li><a href="#genericapiview">GenericAPIView</a></li>
|
||||
<li class="main"><a href="#mixins">Mixins</a></li>
|
||||
<li><a href="#listmodelmixin">ListModelMixin</a></li>
|
||||
<li><a href="#createmodelmixin">CreateModelMixin</a></li>
|
||||
<li><a href="#retrievemodelmixin">RetrieveModelMixin</a></li>
|
||||
<li><a href="#updatemodelmixin">UpdateModelMixin</a></li>
|
||||
<li><a href="#destroymodelmixin">DestroyModelMixin</a></li>
|
||||
<li class="main"><a href="#concrete-view-classes">Concrete View Classes</a></li>
|
||||
<li><a href="#createapiview">CreateAPIView</a></li>
|
||||
<li><a href="#listapiview">ListAPIView</a></li>
|
||||
<li><a href="#retrieveapiview">RetrieveAPIView</a></li>
|
||||
<li><a href="#destroyapiview">DestroyAPIView</a></li>
|
||||
<li><a href="#updateapiview">UpdateAPIView</a></li>
|
||||
<li><a href="#listcreateapiview">ListCreateAPIView</a></li>
|
||||
<li><a href="#retrieveupdateapiview">RetrieveUpdateAPIView</a></li>
|
||||
<li><a href="#retrievedestroyapiview">RetrieveDestroyAPIView</a></li>
|
||||
<li><a href="#retrieveupdatedestroyapiview">RetrieveUpdateDestroyAPIView</a></li>
|
||||
<li class="main"><a href="#customizing-the-generic-views">Customizing the generic views</a></li>
|
||||
<li><a href="#creating-custom-mixins">Creating custom mixins</a></li>
|
||||
<li><a href="#creating-custom-base-classes">Creating custom base classes</a></li>
|
||||
|
||||
<div>
|
||||
<hr>
|
||||
|
||||
<p><strong>The team behind REST framework are launching a new API service.</strong></p>
|
||||
|
||||
<p>If you want to be first in line when we start issuing invitations, please sign up here:</p>
|
||||
|
||||
<!-- Begin MailChimp Signup Form -->
|
||||
<link href="//cdn-images.mailchimp.com/embedcode/slim-081711.css" rel="stylesheet" type="text/css">
|
||||
<style type="text/css">
|
||||
#mc_embed_signup{background:#fff; clear:left; font:14px Helvetica,Arial,sans-serif; }
|
||||
/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
|
||||
We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
|
||||
</style>
|
||||
<div id="mc_embed_signup" style="background: rgb(245, 245, 245)">
|
||||
<form action="http://dabapps.us1.list-manage1.com/subscribe/post?u=cf73a9994eb5b8d8d461b5dfb&id=cb6af8e8bd" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>
|
||||
<!-- <label for="mce-EMAIL">Keep me posted!</label>
|
||||
--> <input style="width: 90%" type="email" value="" name="EMAIL" class="email" id="mce-EMAIL" placeholder="email address" required>
|
||||
<div class="clear"><input class="btn btn-success" type="submit" value="Yes, keep me posted!" name="subscribe" id="mc-embedded-subscribe" class="button"></div>
|
||||
</form>
|
||||
</div>
|
||||
</style></div>
|
||||
</ul>
|
||||
|
||||
|
||||
<!--End mc_embed_signup-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="main-content" class="span9">
|
||||
<p><a class="github" href="https://github.com/tomchristie/django-rest-framework/tree/master/rest_framework/mixins.py"><span class="label label-info">mixins.py</span></a>
|
||||
<a class="github" href="https://github.com/tomchristie/django-rest-framework/tree/master/rest_framework/generics.py"><span class="label label-info">generics.py</span></a></p>
|
||||
<h1 id="generic-views">Generic views</h1>
|
||||
<blockquote>
|
||||
<p>Django’s generic views... were developed as a shortcut for common usage patterns... They take certain common idioms and patterns found in view development and abstract them so that you can quickly write common views of data without having to repeat yourself.</p>
|
||||
<p>— <a href="https://docs.djangoproject.com/en/dev/ref/class-based-views/#base-vs-generic-views">Django Documentation</a></p>
|
||||
</blockquote>
|
||||
<p>One of the key benefits of class based views is the way they allow you to compose bits of reusable behaviour. REST framework takes advantage of this by providing a number of pre-built views that provide for commonly used patterns.</p>
|
||||
<p>The generic views provided by REST framework allow you to quickly build API views that map closely to your database models.</p>
|
||||
<p>If the generic views don't suit the needs of your API, you can drop down to using the regular <code>APIView</code> class, or reuse the mixins and base classes used by the generic views to compose your own set of reusable generic views.</p>
|
||||
<h2 id="examples">Examples</h2>
|
||||
<p>Typically when using the generic views, you'll override the view, and set several class attributes.</p>
|
||||
<pre class="prettyprint lang-py"><code>from django.contrib.auth.models import User
|
||||
from myapp.serializers import UserSerializer
|
||||
from rest_framework import generics
|
||||
from rest_framework.permissions import IsAdminUser
|
||||
|
||||
class UserList(generics.ListCreateAPIView):
|
||||
queryset = User.objects.all()
|
||||
serializer_class = UserSerializer
|
||||
permission_classes = (IsAdminUser,)
|
||||
paginate_by = 100
|
||||
</code></pre>
|
||||
<p>For more complex cases you might also want to override various methods on the view class. For example.</p>
|
||||
<pre class="prettyprint lang-py"><code>class UserList(generics.ListCreateAPIView):
|
||||
queryset = User.objects.all()
|
||||
serializer_class = UserSerializer
|
||||
permission_classes = (IsAdminUser,)
|
||||
|
||||
def get_paginate_by(self):
|
||||
"""
|
||||
Use smaller pagination for HTML representations.
|
||||
"""
|
||||
if self.request.accepted_renderer.format == 'html':
|
||||
return 20
|
||||
return 100
|
||||
</code></pre>
|
||||
<p>For very simple cases you might want to pass through any class attributes using the <code>.as_view()</code> method. For example, your URLconf might include something the following entry.</p>
|
||||
<pre class="prettyprint lang-py"><code>url(r'^/users/', ListCreateAPIView.as_view(model=User), name='user-list')
|
||||
</code></pre>
|
||||
<hr />
|
||||
<h1 id="api-reference">API Reference</h1>
|
||||
<h2 id="genericapiview">GenericAPIView</h2>
|
||||
<p>This class extends REST framework's <code>APIView</code> class, adding commonly required behavior for standard list and detail views.</p>
|
||||
<p>Each of the concrete generic views provided is built by combining <code>GenericAPIView</code>, with one or more mixin classes.</p>
|
||||
<h3 id="attributes">Attributes</h3>
|
||||
<p><strong>Basic settings</strong>:</p>
|
||||
<p>The following attributes control the basic view behavior.</p>
|
||||
<ul>
|
||||
<li><code>queryset</code> - The queryset that should be used for returning objects from this view. Typically, you must either set this attribute, or override the <code>get_queryset()</code> method.</li>
|
||||
<li><code>serializer_class</code> - The serializer class that should be used for validating and deserializing input, and for serializing output. Typically, you must either set this attribute, or override the <code>get_serializer_class()</code> method.</li>
|
||||
<li><code>lookup_field</code> - The model field that should be used to for performing object lookup of individual model instances. Defaults to <code>'pk'</code>. Note that when using hyperlinked APIs you'll need to ensure that <em>both</em> the API views <em>and</em> the serializer classes set the lookup fields if you need to use a custom value.</li>
|
||||
<li><code>lookup_url_kwarg</code> - The URL keyword argument that should be used for object lookup. The URL conf should include a keyword argument corresponding to this value. If unset this defaults to using the same value as <code>lookup_field</code>.</li>
|
||||
</ul>
|
||||
<p><strong>Shortcuts</strong>:</p>
|
||||
<ul>
|
||||
<li><code>model</code> - This shortcut may be used instead of setting either (or both) of the <code>queryset</code>/<code>serializer_class</code> attributes, although using the explicit style is generally preferred. If used instead of <code>serializer_class</code>, then then <code>DEFAULT_MODEL_SERIALIZER_CLASS</code> setting will determine the base serializer class. Note that <code>model</code> is only ever used for generating a default queryset or serializer class - the <code>queryset</code> and <code>serializer_class</code> attributes are always preferred if provided.</li>
|
||||
</ul>
|
||||
<p><strong>Pagination</strong>:</p>
|
||||
<p>The following attributes are used to control pagination when used with list views.</p>
|
||||
<ul>
|
||||
<li><code>paginate_by</code> - The size of pages to use with paginated data. If set to <code>None</code> then pagination is turned off. If unset this uses the same value as the <code>PAGINATE_BY</code> setting, which defaults to <code>None</code>.</li>
|
||||
<li><code>paginate_by_param</code> - The name of a query parameter, which can be used by the client to override the default page size to use for pagination. If unset this uses the same value as the <code>PAGINATE_BY_PARAM</code> setting, which defaults to <code>None</code>.</li>
|
||||
<li><code>pagination_serializer_class</code> - The pagination serializer class to use when determining the style of paginated responses. Defaults to the same value as the <code>DEFAULT_PAGINATION_SERIALIZER_CLASS</code> setting.</li>
|
||||
<li><code>page_kwarg</code> - The name of a URL kwarg or URL query parameter which can be used by the client to control which page is requested. Defaults to <code>'page'</code>.</li>
|
||||
</ul>
|
||||
<p><strong>Filtering</strong>:</p>
|
||||
<ul>
|
||||
<li><code>filter_backends</code> - A list of filter backend classes that should be used for filtering the queryset. Defaults to the same value as the <code>DEFAULT_FILTER_BACKENDS</code> setting.</li>
|
||||
</ul>
|
||||
<h3 id="methods">Methods</h3>
|
||||
<p><strong>Base methods</strong>:</p>
|
||||
<h4 id="get_querysetself"><code>get_queryset(self)</code></h4>
|
||||
<p>Returns the queryset that should be used for list views, and that should be used as the base for lookups in detail views. Defaults to returning the queryset specified by the <code>queryset</code> attribute, or the default queryset for the model if the <code>model</code> shortcut is being used.</p>
|
||||
<p>May be overridden to provide dynamic behavior such as returning a queryset that is specific to the user making the request.</p>
|
||||
<p>For example:</p>
|
||||
<pre class="prettyprint lang-py"><code>def get_queryset(self):
|
||||
user = self.request.user
|
||||
return user.accounts.all()
|
||||
</code></pre>
|
||||
<h4 id="get_objectself"><code>get_object(self)</code></h4>
|
||||
<p>Returns an object instance that should be used for detail views. Defaults to using the <code>lookup_field</code> parameter to filter the base queryset.</p>
|
||||
<p>May be overridden to provide more complex behavior such as object lookups based on more than one URL kwarg.</p>
|
||||
<p>For example:</p>
|
||||
<pre class="prettyprint lang-py"><code>def get_object(self):
|
||||
queryset = self.get_queryset()
|
||||
filter = {}
|
||||
for field in self.multiple_lookup_fields:
|
||||
filter[field] = self.kwargs[field]
|
||||
|
||||
obj = get_object_or_404(queryset, **filter)
|
||||
self.check_object_permissions(self.request, obj)
|
||||
return obj
|
||||
</code></pre>
|
||||
<p>Note that if your API doesn't include any object level permissions, you may optionally exclude the <code>`self.check_object_permissions, and simply return the object from the</code>get_object_or_404` lookup.</p>
|
||||
<h4 id="get_filter_backendsself"><code>get_filter_backends(self)</code></h4>
|
||||
<p>Returns the classes that should be used to filter the queryset. Defaults to returning the <code>filter_backends</code> attribute.</p>
|
||||
<p>May be override to provide more complex behavior with filters, as using different (or even exlusive) lists of filter_backends depending on different criteria.</p>
|
||||
<p>For example:</p>
|
||||
<pre class="prettyprint lang-py"><code>def get_filter_backends(self):
|
||||
if "geo_route" in self.request.QUERY_PARAMS:
|
||||
return (GeoRouteFilter, CategoryFilter)
|
||||
elif "geo_point" in self.request.QUERY_PARAMS:
|
||||
return (GeoPointFilter, CategoryFilter)
|
||||
|
||||
return (CategoryFilter,)
|
||||
</code></pre>
|
||||
<h4 id="get_serializer_classself"><code>get_serializer_class(self)</code></h4>
|
||||
<p>Returns the class that should be used for the serializer. Defaults to returning the <code>serializer_class</code> attribute, or dynamically generating a serializer class if the <code>model</code> shortcut is being used.</p>
|
||||
<p>May be override to provide dynamic behavior such as using different serializers for read and write operations, or providing different serializers to different types of users.</p>
|
||||
<p>For example:</p>
|
||||
<pre class="prettyprint lang-py"><code>def get_serializer_class(self):
|
||||
if self.request.user.is_staff:
|
||||
return FullAccountSerializer
|
||||
return BasicAccountSerializer
|
||||
</code></pre>
|
||||
<h4 id="get_paginate_byself"><code>get_paginate_by(self)</code></h4>
|
||||
<p>Returns the page size to use with pagination. By default this uses the <code>paginate_by</code> attribute, and may be overridden by the client if the <code>paginate_by_param</code> attribute is set.</p>
|
||||
<p>You may want to override this method to provide more complex behavior such as modifying page sizes based on the media type of the response.</p>
|
||||
<p>For example:</p>
|
||||
<pre class="prettyprint lang-py"><code>def get_paginate_by(self):
|
||||
if self.request.accepted_renderer.format == 'html':
|
||||
return 20
|
||||
return 100
|
||||
</code></pre>
|
||||
<p><strong>Save hooks</strong>:</p>
|
||||
<p>The following methods are provided as placeholder interfaces. They contain empty implementations and are not called directly by <code>GenericAPIView</code>, but they are overridden and used by some of the mixin classes.</p>
|
||||
<ul>
|
||||
<li><code>pre_save(self, obj)</code> - A hook that is called before saving an object.</li>
|
||||
<li><code>post_save(self, obj, created=False)</code> - A hook that is called after saving an object.</li>
|
||||
</ul>
|
||||
<p>The <code>pre_save</code> method in particular is a useful hook for setting attributes that are implicit in the request, but are not part of the request data. For instance, you might set an attribute on the object based on the request user, or based on a URL keyword argument.</p>
|
||||
<pre class="prettyprint lang-py"><code>def pre_save(self, obj):
|
||||
"""
|
||||
Set the object's owner, based on the incoming request.
|
||||
"""
|
||||
obj.owner = self.request.user
|
||||
</code></pre>
|
||||
<p>Remember that the <code>pre_save()</code> method is not called by <code>GenericAPIView</code> itself, but it is called by <code>create()</code> and <code>update()</code> methods on the <code>CreateModelMixin</code> and <code>UpdateModelMixin</code> classes.</p>
|
||||
<p><strong>Other methods</strong>:</p>
|
||||
<p>You won't typically need to override the following methods, although you might need to call into them if you're writing custom views using <code>GenericAPIView</code>.</p>
|
||||
<ul>
|
||||
<li><code>get_serializer_context(self)</code> - Returns a dictionary containing any extra context that should be supplied to the serializer. Defaults to including <code>'request'</code>, <code>'view'</code> and <code>'format'</code> keys.</li>
|
||||
<li><code>get_serializer(self, instance=None, data=None, files=None, many=False, partial=False)</code> - Returns a serializer instance.</li>
|
||||
<li><code>get_pagination_serializer(self, page)</code> - Returns a serializer instance to use with paginated data.</li>
|
||||
<li><code>paginate_queryset(self, queryset)</code> - Paginate a queryset if required, either returning a page object, or <code>None</code> if pagination is not configured for this view.</li>
|
||||
<li><code>filter_queryset(self, queryset)</code> - Given a queryset, filter it with whichever filter backends are in use, returning a new queryset.</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h1 id="mixins">Mixins</h1>
|
||||
<p>The mixin classes provide the actions that are used to provide the basic view behavior. Note that the mixin classes provide action methods rather than defining the handler methods such as <code>.get()</code> and <code>.post()</code> directly. This allows for more flexible composition of behavior.</p>
|
||||
<h2 id="listmodelmixin">ListModelMixin</h2>
|
||||
<p>Provides a <code>.list(request, *args, **kwargs)</code> method, that implements listing a queryset.</p>
|
||||
<p>If the queryset is populated, this returns a <code>200 OK</code> response, with a serialized representation of the queryset as the body of the response. The response data may optionally be paginated.</p>
|
||||
<p>If the queryset is empty this returns a <code>200 OK</code> response, unless the <code>.allow_empty</code> attribute on the view is set to <code>False</code>, in which case it will return a <code>404 Not Found</code>.</p>
|
||||
<h2 id="createmodelmixin">CreateModelMixin</h2>
|
||||
<p>Provides a <code>.create(request, *args, **kwargs)</code> method, that implements creating and saving a new model instance.</p>
|
||||
<p>If an object is created this returns a <code>201 Created</code> response, with a serialized representation of the object as the body of the response. If the representation contains a key named <code>url</code>, then the <code>Location</code> header of the response will be populated with that value.</p>
|
||||
<p>If the request data provided for creating the object was invalid, a <code>400 Bad Request</code> response will be returned, with the error details as the body of the response.</p>
|
||||
<h2 id="retrievemodelmixin">RetrieveModelMixin</h2>
|
||||
<p>Provides a <code>.retrieve(request, *args, **kwargs)</code> method, that implements returning an existing model instance in a response.</p>
|
||||
<p>If an object can be retrieved this returns a <code>200 OK</code> response, with a serialized representation of the object as the body of the response. Otherwise it will return a <code>404 Not Found</code>.</p>
|
||||
<h2 id="updatemodelmixin">UpdateModelMixin</h2>
|
||||
<p>Provides a <code>.update(request, *args, **kwargs)</code> method, that implements updating and saving an existing model instance.</p>
|
||||
<p>Also provides a <code>.partial_update(request, *args, **kwargs)</code> method, which is similar to the <code>update</code> method, except that all fields for the update will be optional. This allows support for HTTP <code>PATCH</code> requests.</p>
|
||||
<p>If an object is updated this returns a <code>200 OK</code> response, with a serialized representation of the object as the body of the response.</p>
|
||||
<p>If an object is created, for example when making a <code>DELETE</code> request followed by a <code>PUT</code> request to the same URL, this returns a <code>201 Created</code> response, with a serialized representation of the object as the body of the response.</p>
|
||||
<p>If the request data provided for updating the object was invalid, a <code>400 Bad Request</code> response will be returned, with the error details as the body of the response.</p>
|
||||
<h2 id="destroymodelmixin">DestroyModelMixin</h2>
|
||||
<p>Provides a <code>.destroy(request, *args, **kwargs)</code> method, that implements deletion of an existing model instance.</p>
|
||||
<p>If an object is deleted this returns a <code>204 No Content</code> response, otherwise it will return a <code>404 Not Found</code>.</p>
|
||||
<hr />
|
||||
<h1 id="concrete-view-classes">Concrete View Classes</h1>
|
||||
<p>The following classes are the concrete generic views. If you're using generic views this is normally the level you'll be working at unless you need heavily customized behavior.</p>
|
||||
<h2 id="createapiview">CreateAPIView</h2>
|
||||
<p>Used for <strong>create-only</strong> endpoints.</p>
|
||||
<p>Provides a <code>post</code> method handler.</p>
|
||||
<p>Extends: <a href="#genericapiview">GenericAPIView</a>, <a href="#createmodelmixin">CreateModelMixin</a></p>
|
||||
<h2 id="listapiview">ListAPIView</h2>
|
||||
<p>Used for <strong>read-only</strong> endpoints to represent a <strong>collection of model instances</strong>.</p>
|
||||
<p>Provides a <code>get</code> method handler.</p>
|
||||
<p>Extends: <a href="#genericapiview">GenericAPIView</a>, <a href="#listmodelmixin">ListModelMixin</a></p>
|
||||
<h2 id="retrieveapiview">RetrieveAPIView</h2>
|
||||
<p>Used for <strong>read-only</strong> endpoints to represent a <strong>single model instance</strong>.</p>
|
||||
<p>Provides a <code>get</code> method handler.</p>
|
||||
<p>Extends: <a href="#genericapiview">GenericAPIView</a>, <a href="#retrievemodelmixin">RetrieveModelMixin</a></p>
|
||||
<h2 id="destroyapiview">DestroyAPIView</h2>
|
||||
<p>Used for <strong>delete-only</strong> endpoints for a <strong>single model instance</strong>.</p>
|
||||
<p>Provides a <code>delete</code> method handler.</p>
|
||||
<p>Extends: <a href="#genericapiview">GenericAPIView</a>, <a href="#destroymodelmixin">DestroyModelMixin</a></p>
|
||||
<h2 id="updateapiview">UpdateAPIView</h2>
|
||||
<p>Used for <strong>update-only</strong> endpoints for a <strong>single model instance</strong>.</p>
|
||||
<p>Provides <code>put</code> and <code>patch</code> method handlers.</p>
|
||||
<p>Extends: <a href="#genericapiview">GenericAPIView</a>, <a href="#updatemodelmixin">UpdateModelMixin</a></p>
|
||||
<h2 id="listcreateapiview">ListCreateAPIView</h2>
|
||||
<p>Used for <strong>read-write</strong> endpoints to represent a <strong>collection of model instances</strong>.</p>
|
||||
<p>Provides <code>get</code> and <code>post</code> method handlers.</p>
|
||||
<p>Extends: <a href="#genericapiview">GenericAPIView</a>, <a href="#listmodelmixin">ListModelMixin</a>, <a href="#createmodelmixin">CreateModelMixin</a></p>
|
||||
<h2 id="retrieveupdateapiview">RetrieveUpdateAPIView</h2>
|
||||
<p>Used for <strong>read or update</strong> endpoints to represent a <strong>single model instance</strong>.</p>
|
||||
<p>Provides <code>get</code>, <code>put</code> and <code>patch</code> method handlers.</p>
|
||||
<p>Extends: <a href="#genericapiview">GenericAPIView</a>, <a href="#retrievemodelmixin">RetrieveModelMixin</a>, <a href="#updatemodelmixin">UpdateModelMixin</a></p>
|
||||
<h2 id="retrievedestroyapiview">RetrieveDestroyAPIView</h2>
|
||||
<p>Used for <strong>read or delete</strong> endpoints to represent a <strong>single model instance</strong>.</p>
|
||||
<p>Provides <code>get</code> and <code>delete</code> method handlers.</p>
|
||||
<p>Extends: <a href="#genericapiview">GenericAPIView</a>, <a href="#retrievemodelmixin">RetrieveModelMixin</a>, <a href="#destroymodelmixin">DestroyModelMixin</a></p>
|
||||
<h2 id="retrieveupdatedestroyapiview">RetrieveUpdateDestroyAPIView</h2>
|
||||
<p>Used for <strong>read-write-delete</strong> endpoints to represent a <strong>single model instance</strong>.</p>
|
||||
<p>Provides <code>get</code>, <code>put</code>, <code>patch</code> and <code>delete</code> method handlers.</p>
|
||||
<p>Extends: <a href="#genericapiview">GenericAPIView</a>, <a href="#retrievemodelmixin">RetrieveModelMixin</a>, <a href="#updatemodelmixin">UpdateModelMixin</a>, <a href="#destroymodelmixin">DestroyModelMixin</a></p>
|
||||
<hr />
|
||||
<h1 id="customizing-the-generic-views">Customizing the generic views</h1>
|
||||
<p>Often you'll want to use the existing generic views, but use some slightly customized behavior. If you find yourself reusing some bit of customized behavior in multiple places, you might want to refactor the behavior into a common class that you can then just apply to any view or viewset as needed.</p>
|
||||
<h2 id="creating-custom-mixins">Creating custom mixins</h2>
|
||||
<p>For example, if you need to lookup objects based on multiple fields in the URL conf, you could create a mixin class like the following:</p>
|
||||
<pre class="prettyprint lang-py"><code>class MultipleFieldLookupMixin(object):
|
||||
"""
|
||||
Apply this mixin to any view or viewset to get multiple field filtering
|
||||
based on a `lookup_fields` attribute, instead of the default single field filtering.
|
||||
"""
|
||||
def get_object(self):
|
||||
queryset = self.get_queryset() # Get the base queryset
|
||||
queryset = self.filter_queryset(queryset) # Apply any filter backends
|
||||
filter = {}
|
||||
for field in self.lookup_fields:
|
||||
filter[field] = self.kwargs[field]
|
||||
return get_object_or_404(queryset, **filter) # Lookup the object
|
||||
</code></pre>
|
||||
<p>You can then simply apply this mixin to a view or viewset anytime you need to apply the custom behavior.</p>
|
||||
<pre class="prettyprint lang-py"><code>class RetrieveUserView(MultipleFieldLookupMixin, generics.RetrieveAPIView):
|
||||
queryset = User.objects.all()
|
||||
serializer_class = UserSerializer
|
||||
lookup_fields = ('account', 'username')
|
||||
</code></pre>
|
||||
<p>Using custom mixins is a good option if you have custom behavior that needs to be used</p>
|
||||
<h2 id="creating-custom-base-classes">Creating custom base classes</h2>
|
||||
<p>If you are using a mixin across multiple views, you can take this a step further and create your own set of base views that can then be used throughout your project. For example:</p>
|
||||
<pre class="prettyprint lang-py"><code>class BaseRetrieveView(MultipleFieldLookupMixin,
|
||||
generics.RetrieveAPIView):
|
||||
pass
|
||||
|
||||
class BaseRetrieveUpdateDestroyView(MultipleFieldLookupMixin,
|
||||
generics.RetrieveUpdateDestroyAPIView):
|
||||
pass
|
||||
</code></pre>
|
||||
<p>Using custom base classes is a good option if you have custom behavior that consistently needs to be repeated across a large number of views throughout your project.</p>
|
||||
</div><!--/span-->
|
||||
</div><!--/row-->
|
||||
</div><!--/.fluid-container-->
|
||||
</div><!--/.body content-->
|
||||
|
||||
<div id="push"></div>
|
||||
</div><!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a></p>
|
||||
</footer>
|
||||
|
||||
<!-- Le javascript
|
||||
================================================== -->
|
||||
<!-- Placed at the end of the document so the pages load faster -->
|
||||
<script src="http://django-rest-framework.org/js/jquery-1.8.1-min.js"></script>
|
||||
<script src="http://django-rest-framework.org/js/prettify-1.0.js"></script>
|
||||
<script src="http://django-rest-framework.org/js/bootstrap-2.1.1-min.js"></script>
|
||||
<script>
|
||||
//$('.side-nav').scrollspy()
|
||||
var shiftWindow = function() { scrollBy(0, -50) };
|
||||
if (location.hash) shiftWindow();
|
||||
window.addEventListener("hashchange", shiftWindow);
|
||||
|
||||
$('.dropdown-menu').on('click touchstart', function(event) {
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
// Dynamically force sidenav to no higher than browser window
|
||||
$('.side-nav').css('max-height', window.innerHeight - 130);
|
||||
|
||||
$(function(){
|
||||
$(window).resize(function(){
|
||||
$('.side-nav').css('max-height', window.innerHeight - 130);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body></html>
|
||||
366
api-guide/pagination.html
Normal file
366
api-guide/pagination.html
Normal file
|
|
@ -0,0 +1,366 @@
|
|||
<!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 - Pagination</title>
|
||||
<link href="http://django-rest-framework.org/img/favicon.ico" rel="icon" type="image/x-icon">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Django, API, REST, Pagination, Custom pagination serializers">
|
||||
<meta name="author" content="Tom Christie">
|
||||
|
||||
<!-- Le styles -->
|
||||
<link href="http://django-rest-framework.org/css/prettify.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/bootstrap.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/bootstrap-responsive.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/default.css" rel="stylesheet">
|
||||
|
||||
<!-- 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]-->
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-18852272-2']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="prettyPrint()" class="pagination-page">
|
||||
|
||||
<div class="wrapper">
|
||||
|
||||
<div class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container-fluid">
|
||||
<a class="repo-link btn btn-primary btn-small" href="https://github.com/tomchristie/django-rest-framework/tree/master">GitHub</a>
|
||||
<a class="repo-link btn btn-inverse btn-small " href="../api-guide/content-negotiation.html">Next <i class="icon-arrow-right icon-white"></i></a>
|
||||
<a class="repo-link btn btn-inverse btn-small " href="../api-guide/filtering.html"><i class="icon-arrow-left icon-white"></i> Previous</a>
|
||||
<a class="repo-link btn btn-inverse btn-small" href="#searchModal" data-toggle="modal"><i class="icon-search icon-white"></i> Search</a>
|
||||
<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>
|
||||
<a class="brand" href="http://django-rest-framework.org">Django REST framework</a>
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav">
|
||||
<li><a href="http://django-rest-framework.org">Home</a></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Tutorial <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/tutorial/quickstart.html">Quickstart</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/1-serialization.html">1 - Serialization</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/2-requests-and-responses.html">2 - Requests and responses</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/3-class-based-views.html">3 - Class based views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/4-authentication-and-permissions.html">4 - Authentication and permissions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/5-relationships-and-hyperlinked-apis.html">5 - Relationships and hyperlinked APIs</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/6-viewsets-and-routers.html">6 - Viewsets and routers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">API Guide <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/api-guide/requests.html">Requests</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/responses.html">Responses</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/views.html">Views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/generic-views.html">Generic views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/viewsets.html">Viewsets</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/routers.html">Routers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/parsers.html">Parsers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/renderers.html">Renderers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/serializers.html">Serializers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/fields.html">Serializer fields</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/relations.html">Serializer relations</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/authentication.html">Authentication</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/permissions.html">Permissions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/throttling.html">Throttling</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/filtering.html">Filtering</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/pagination.html">Pagination</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/content-negotiation.html">Content negotiation</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/format-suffixes.html">Format suffixes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/reverse.html">Returning URLs</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/exceptions.html">Exceptions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/status-codes.html">Status codes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/testing.html">Testing</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/settings.html">Settings</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Topics <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/topics/documenting-your-api.html">Documenting your API</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/ajax-csrf-cors.html">AJAX, CSRF & CORS</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/browser-enhancements.html">Browser enhancements</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/browsable-api.html">The Browsable API</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/rest-hypermedia-hateoas.html">REST, Hypermedia & HATEOAS</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/rest-framework-2-announcement.html">2.0 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/2.2-announcement.html">2.2 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/2.3-announcement.html">2.3 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/release-notes.html">Release Notes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/credits.html">Credits</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="nav pull-right">
|
||||
<!-- TODO
|
||||
<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>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="body-content">
|
||||
<div class="container-fluid">
|
||||
|
||||
<!-- Search Modal -->
|
||||
<div id="searchModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3 id="myModalLabel">Documentation search</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<!-- Custom google search -->
|
||||
<script>
|
||||
(function() {
|
||||
var cx = '015016005043623903336:rxraeohqk6w';
|
||||
var gcse = document.createElement('script');
|
||||
gcse.type = 'text/javascript';
|
||||
gcse.async = true;
|
||||
gcse.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') +
|
||||
'//www.google.com/cse/cse.js?cx=' + cx;
|
||||
var s = document.getElementsByTagName('script')[0];
|
||||
s.parentNode.insertBefore(gcse, s);
|
||||
})();
|
||||
</script>
|
||||
<gcse:search></gcse:search>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row-fluid">
|
||||
|
||||
<div class="span3">
|
||||
<!-- TODO
|
||||
<p style="margin-top: -12px">
|
||||
<a class="btn btn-mini btn-primary" style="width: 60px">« previous</a>
|
||||
<a class="btn btn-mini btn-primary" style="float: right; margin-right: 8px; width: 60px;">next »</a>
|
||||
</p>
|
||||
-->
|
||||
<div id="table-of-contents">
|
||||
<ul class="nav nav-list side-nav well sidebar-nav-fixed">
|
||||
<li class="main"><a href="#pagination">Pagination</a></li>
|
||||
<li><a href="#paginating-basic-data">Paginating basic data</a></li>
|
||||
<li><a href="#paginating-querysets">Paginating QuerySets</a></li>
|
||||
<li><a href="#pagination-in-the-generic-views">Pagination in the generic views</a></li>
|
||||
<li class="main"><a href="#custom-pagination-serializers">Custom pagination serializers</a></li>
|
||||
<li><a href="#example">Example</a></li>
|
||||
<li><a href="#using-your-custom-pagination-serializer">Using your custom pagination serializer</a></li>
|
||||
|
||||
<div>
|
||||
<hr>
|
||||
|
||||
<p><strong>The team behind REST framework are launching a new API service.</strong></p>
|
||||
|
||||
<p>If you want to be first in line when we start issuing invitations, please sign up here:</p>
|
||||
|
||||
<!-- Begin MailChimp Signup Form -->
|
||||
<link href="//cdn-images.mailchimp.com/embedcode/slim-081711.css" rel="stylesheet" type="text/css">
|
||||
<style type="text/css">
|
||||
#mc_embed_signup{background:#fff; clear:left; font:14px Helvetica,Arial,sans-serif; }
|
||||
/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
|
||||
We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
|
||||
</style>
|
||||
<div id="mc_embed_signup" style="background: rgb(245, 245, 245)">
|
||||
<form action="http://dabapps.us1.list-manage1.com/subscribe/post?u=cf73a9994eb5b8d8d461b5dfb&id=cb6af8e8bd" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>
|
||||
<!-- <label for="mce-EMAIL">Keep me posted!</label>
|
||||
--> <input style="width: 90%" type="email" value="" name="EMAIL" class="email" id="mce-EMAIL" placeholder="email address" required>
|
||||
<div class="clear"><input class="btn btn-success" type="submit" value="Yes, keep me posted!" name="subscribe" id="mc-embedded-subscribe" class="button"></div>
|
||||
</form>
|
||||
</div>
|
||||
</style></div>
|
||||
</ul>
|
||||
|
||||
|
||||
<!--End mc_embed_signup-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="main-content" class="span9">
|
||||
<p><a class="github" href="https://github.com/tomchristie/django-rest-framework/tree/master/rest_framework/pagination.py"><span class="label label-info">pagination.py</span></a></p>
|
||||
<h1 id="pagination">Pagination</h1>
|
||||
<blockquote>
|
||||
<p>Django provides a few classes that help you manage paginated data – that is, data that’s split across several pages, with “Previous/Next” links.</p>
|
||||
<p>— <a href="https://docs.djangoproject.com/en/dev/topics/pagination/">Django documentation</a></p>
|
||||
</blockquote>
|
||||
<p>REST framework includes a <code>PaginationSerializer</code> class that makes it easy to return paginated data in a way that can then be rendered to arbitrary media types. </p>
|
||||
<h2 id="paginating-basic-data">Paginating basic data</h2>
|
||||
<p>Let's start by taking a look at an example from the Django documentation.</p>
|
||||
<pre class="prettyprint lang-py"><code>from django.core.paginator import Paginator
|
||||
|
||||
objects = ['john', 'paul', 'george', 'ringo']
|
||||
paginator = Paginator(objects, 2)
|
||||
page = paginator.page(1)
|
||||
page.object_list
|
||||
# ['john', 'paul']
|
||||
</code></pre>
|
||||
<p>At this point we've got a page object. If we wanted to return this page object as a JSON response, we'd need to provide the client with context such as next and previous links, so that it would be able to page through the remaining results.</p>
|
||||
<pre class="prettyprint lang-py"><code>from rest_framework.pagination import PaginationSerializer
|
||||
|
||||
serializer = PaginationSerializer(instance=page)
|
||||
serializer.data
|
||||
# {'count': 4, 'next': '?page=2', 'previous': None, 'results': [u'john', u'paul']}
|
||||
</code></pre>
|
||||
<p>The <code>context</code> argument of the <code>PaginationSerializer</code> class may optionally include the request. If the request is included in the context then the next and previous links returned by the serializer will use absolute URLs instead of relative URLs.</p>
|
||||
<pre class="prettyprint lang-py"><code>request = RequestFactory().get('/foobar')
|
||||
serializer = PaginationSerializer(instance=page, context={'request': request})
|
||||
serializer.data
|
||||
# {'count': 4, 'next': 'http://testserver/foobar?page=2', 'previous': None, 'results': [u'john', u'paul']}
|
||||
</code></pre>
|
||||
<p>We could now return that data in a <code>Response</code> object, and it would be rendered into the correct media type.</p>
|
||||
<h2 id="paginating-querysets">Paginating QuerySets</h2>
|
||||
<p>Our first example worked because we were using primitive objects. If we wanted to paginate a queryset or other complex data, we'd need to specify a serializer to use to serialize the result set itself.</p>
|
||||
<p>We can do this using the <code>object_serializer_class</code> attribute on the inner <code>Meta</code> class of the pagination serializer. For example.</p>
|
||||
<pre class="prettyprint lang-py"><code>class UserSerializer(serializers.ModelSerializer):
|
||||
"""
|
||||
Serializes user querysets.
|
||||
"""
|
||||
class Meta:
|
||||
model = User
|
||||
fields = ('username', 'email')
|
||||
|
||||
class PaginatedUserSerializer(pagination.PaginationSerializer):
|
||||
"""
|
||||
Serializes page objects of user querysets.
|
||||
"""
|
||||
class Meta:
|
||||
object_serializer_class = UserSerializer
|
||||
</code></pre>
|
||||
<p>We could now use our pagination serializer in a view like this.</p>
|
||||
<pre class="prettyprint lang-py"><code>@api_view('GET')
|
||||
def user_list(request):
|
||||
queryset = User.objects.all()
|
||||
paginator = Paginator(queryset, 20)
|
||||
|
||||
page = request.QUERY_PARAMS.get('page')
|
||||
try:
|
||||
users = paginator.page(page)
|
||||
except PageNotAnInteger:
|
||||
# If page is not an integer, deliver first page.
|
||||
users = paginator.page(1)
|
||||
except EmptyPage:
|
||||
# If page is out of range (e.g. 9999),
|
||||
# deliver last page of results.
|
||||
users = paginator.page(paginator.num_pages)
|
||||
|
||||
serializer_context = {'request': request}
|
||||
serializer = PaginatedUserSerializer(users,
|
||||
context=serializer_context)
|
||||
return Response(serializer.data)
|
||||
</code></pre>
|
||||
<h2 id="pagination-in-the-generic-views">Pagination in the generic views</h2>
|
||||
<p>The generic class based views <code>ListAPIView</code> and <code>ListCreateAPIView</code> provide pagination of the returned querysets by default. You can customise this behaviour by altering the pagination style, by modifying the default number of results, by allowing clients to override the page size using a query parameter, or by turning pagination off completely.</p>
|
||||
<p>The default pagination style may be set globally, using the <code>DEFAULT_PAGINATION_SERIALIZER_CLASS</code>, <code>PAGINATE_BY</code>, <code>PAGINATE_BY_PARAM</code>, and <code>MAX_PAGINATE_BY</code> settings. For example.</p>
|
||||
<pre class="prettyprint lang-py"><code>REST_FRAMEWORK = {
|
||||
'PAGINATE_BY': 10, # Default to 10
|
||||
'PAGINATE_BY_PARAM': 'page_size', # Allow client to override, using `?page_size=xxx`.
|
||||
'MAX_PAGINATE_BY': 100 # Maximum limit allowed when using `?page_size=xxx`.
|
||||
}
|
||||
</code></pre>
|
||||
<p>You can also set the pagination style on a per-view basis, using the <code>ListAPIView</code> generic class-based view.</p>
|
||||
<pre class="prettyprint lang-py"><code>class PaginatedListView(ListAPIView):
|
||||
queryset = ExampleModel.objects.all()
|
||||
serializer_class = ExampleModelSerializer
|
||||
paginate_by = 10
|
||||
paginate_by_param = 'page_size'
|
||||
max_paginate_by = 100
|
||||
</code></pre>
|
||||
<p>Note that using a <code>paginate_by</code> value of <code>None</code> will turn off pagination for the view.</p>
|
||||
<p>For more complex requirements such as serialization that differs depending on the requested media type you can override the <code>.get_paginate_by()</code> and <code>.get_pagination_serializer_class()</code> methods.</p>
|
||||
<hr />
|
||||
<h1 id="custom-pagination-serializers">Custom pagination serializers</h1>
|
||||
<p>To create a custom pagination serializer class you should override <code>pagination.BasePaginationSerializer</code> and set the fields that you want the serializer to return.</p>
|
||||
<p>You can also override the name used for the object list field, by setting the <code>results_field</code> attribute, which defaults to <code>'results'</code>.</p>
|
||||
<h2 id="example">Example</h2>
|
||||
<p>For example, to nest a pair of links labelled 'prev' and 'next', and set the name for the results field to 'objects', you might use something like this.</p>
|
||||
<pre class="prettyprint lang-py"><code>from rest_framework import pagination
|
||||
from rest_framework import serializers
|
||||
|
||||
class LinksSerializer(serializers.Serializer):
|
||||
next = pagination.NextPageField(source='*')
|
||||
prev = pagination.PreviousPageField(source='*')
|
||||
|
||||
class CustomPaginationSerializer(pagination.BasePaginationSerializer):
|
||||
links = LinksSerializer(source='*') # Takes the page object as the source
|
||||
total_results = serializers.Field(source='paginator.count')
|
||||
|
||||
results_field = 'objects'
|
||||
</code></pre>
|
||||
<h2 id="using-your-custom-pagination-serializer">Using your custom pagination serializer</h2>
|
||||
<p>To have your custom pagination serializer be used by default, use the <code>DEFAULT_PAGINATION_SERIALIZER_CLASS</code> setting:</p>
|
||||
<pre class="prettyprint lang-py"><code>REST_FRAMEWORK = {
|
||||
'DEFAULT_PAGINATION_SERIALIZER_CLASS':
|
||||
'example_app.pagination.CustomPaginationSerializer',
|
||||
}
|
||||
</code></pre>
|
||||
<p>Alternatively, to set your custom pagination serializer on a per-view basis, use the <code>pagination_serializer_class</code> attribute on a generic class based view:</p>
|
||||
<pre class="prettyprint lang-py"><code>class PaginatedListView(generics.ListAPIView):
|
||||
model = ExampleModel
|
||||
pagination_serializer_class = CustomPaginationSerializer
|
||||
paginate_by = 10
|
||||
</code></pre>
|
||||
</div><!--/span-->
|
||||
</div><!--/row-->
|
||||
</div><!--/.fluid-container-->
|
||||
</div><!--/.body content-->
|
||||
|
||||
<div id="push"></div>
|
||||
</div><!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a></p>
|
||||
</footer>
|
||||
|
||||
<!-- Le javascript
|
||||
================================================== -->
|
||||
<!-- Placed at the end of the document so the pages load faster -->
|
||||
<script src="http://django-rest-framework.org/js/jquery-1.8.1-min.js"></script>
|
||||
<script src="http://django-rest-framework.org/js/prettify-1.0.js"></script>
|
||||
<script src="http://django-rest-framework.org/js/bootstrap-2.1.1-min.js"></script>
|
||||
<script>
|
||||
//$('.side-nav').scrollspy()
|
||||
var shiftWindow = function() { scrollBy(0, -50) };
|
||||
if (location.hash) shiftWindow();
|
||||
window.addEventListener("hashchange", shiftWindow);
|
||||
|
||||
$('.dropdown-menu').on('click touchstart', function(event) {
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
// Dynamically force sidenav to no higher than browser window
|
||||
$('.side-nav').css('max-height', window.innerHeight - 130);
|
||||
|
||||
$(function(){
|
||||
$(window).resize(function(){
|
||||
$('.side-nav').css('max-height', window.innerHeight - 130);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body></html>
|
||||
376
api-guide/parsers.html
Normal file
376
api-guide/parsers.html
Normal file
|
|
@ -0,0 +1,376 @@
|
|||
<!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 - Parsers</title>
|
||||
<link href="http://django-rest-framework.org/img/favicon.ico" rel="icon" type="image/x-icon">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Django, API, REST, Parsers, API Reference, Custom parsers, Third party packages">
|
||||
<meta name="author" content="Tom Christie">
|
||||
|
||||
<!-- Le styles -->
|
||||
<link href="http://django-rest-framework.org/css/prettify.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/bootstrap.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/bootstrap-responsive.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/default.css" rel="stylesheet">
|
||||
|
||||
<!-- 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]-->
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-18852272-2']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="prettyPrint()" class="parsers-page">
|
||||
|
||||
<div class="wrapper">
|
||||
|
||||
<div class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container-fluid">
|
||||
<a class="repo-link btn btn-primary btn-small" href="https://github.com/tomchristie/django-rest-framework/tree/master">GitHub</a>
|
||||
<a class="repo-link btn btn-inverse btn-small " href="../api-guide/renderers.html">Next <i class="icon-arrow-right icon-white"></i></a>
|
||||
<a class="repo-link btn btn-inverse btn-small " href="../api-guide/routers.html"><i class="icon-arrow-left icon-white"></i> Previous</a>
|
||||
<a class="repo-link btn btn-inverse btn-small" href="#searchModal" data-toggle="modal"><i class="icon-search icon-white"></i> Search</a>
|
||||
<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>
|
||||
<a class="brand" href="http://django-rest-framework.org">Django REST framework</a>
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav">
|
||||
<li><a href="http://django-rest-framework.org">Home</a></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Tutorial <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/tutorial/quickstart.html">Quickstart</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/1-serialization.html">1 - Serialization</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/2-requests-and-responses.html">2 - Requests and responses</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/3-class-based-views.html">3 - Class based views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/4-authentication-and-permissions.html">4 - Authentication and permissions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/5-relationships-and-hyperlinked-apis.html">5 - Relationships and hyperlinked APIs</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/6-viewsets-and-routers.html">6 - Viewsets and routers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">API Guide <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/api-guide/requests.html">Requests</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/responses.html">Responses</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/views.html">Views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/generic-views.html">Generic views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/viewsets.html">Viewsets</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/routers.html">Routers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/parsers.html">Parsers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/renderers.html">Renderers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/serializers.html">Serializers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/fields.html">Serializer fields</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/relations.html">Serializer relations</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/authentication.html">Authentication</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/permissions.html">Permissions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/throttling.html">Throttling</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/filtering.html">Filtering</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/pagination.html">Pagination</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/content-negotiation.html">Content negotiation</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/format-suffixes.html">Format suffixes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/reverse.html">Returning URLs</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/exceptions.html">Exceptions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/status-codes.html">Status codes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/testing.html">Testing</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/settings.html">Settings</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Topics <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/topics/documenting-your-api.html">Documenting your API</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/ajax-csrf-cors.html">AJAX, CSRF & CORS</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/browser-enhancements.html">Browser enhancements</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/browsable-api.html">The Browsable API</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/rest-hypermedia-hateoas.html">REST, Hypermedia & HATEOAS</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/rest-framework-2-announcement.html">2.0 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/2.2-announcement.html">2.2 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/2.3-announcement.html">2.3 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/release-notes.html">Release Notes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/credits.html">Credits</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="nav pull-right">
|
||||
<!-- TODO
|
||||
<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>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="body-content">
|
||||
<div class="container-fluid">
|
||||
|
||||
<!-- Search Modal -->
|
||||
<div id="searchModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3 id="myModalLabel">Documentation search</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<!-- Custom google search -->
|
||||
<script>
|
||||
(function() {
|
||||
var cx = '015016005043623903336:rxraeohqk6w';
|
||||
var gcse = document.createElement('script');
|
||||
gcse.type = 'text/javascript';
|
||||
gcse.async = true;
|
||||
gcse.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') +
|
||||
'//www.google.com/cse/cse.js?cx=' + cx;
|
||||
var s = document.getElementsByTagName('script')[0];
|
||||
s.parentNode.insertBefore(gcse, s);
|
||||
})();
|
||||
</script>
|
||||
<gcse:search></gcse:search>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row-fluid">
|
||||
|
||||
<div class="span3">
|
||||
<!-- TODO
|
||||
<p style="margin-top: -12px">
|
||||
<a class="btn btn-mini btn-primary" style="width: 60px">« previous</a>
|
||||
<a class="btn btn-mini btn-primary" style="float: right; margin-right: 8px; width: 60px;">next »</a>
|
||||
</p>
|
||||
-->
|
||||
<div id="table-of-contents">
|
||||
<ul class="nav nav-list side-nav well sidebar-nav-fixed">
|
||||
<li class="main"><a href="#parsers">Parsers</a></li>
|
||||
<li><a href="#how-the-parser-is-determined">How the parser is determined</a></li>
|
||||
<li><a href="#setting-the-parsers">Setting the parsers</a></li>
|
||||
<li class="main"><a href="#api-reference">API Reference</a></li>
|
||||
<li><a href="#jsonparser">JSONParser</a></li>
|
||||
<li><a href="#yamlparser">YAMLParser</a></li>
|
||||
<li><a href="#xmlparser">XMLParser</a></li>
|
||||
<li><a href="#formparser">FormParser</a></li>
|
||||
<li><a href="#multipartparser">MultiPartParser</a></li>
|
||||
<li><a href="#fileuploadparser">FileUploadParser</a></li>
|
||||
<li class="main"><a href="#custom-parsers">Custom parsers</a></li>
|
||||
<li><a href="#example">Example</a></li>
|
||||
<li class="main"><a href="#third-party-packages">Third party packages</a></li>
|
||||
<li><a href="#messagepack">MessagePack</a></li>
|
||||
|
||||
<div>
|
||||
<hr>
|
||||
|
||||
<p><strong>The team behind REST framework are launching a new API service.</strong></p>
|
||||
|
||||
<p>If you want to be first in line when we start issuing invitations, please sign up here:</p>
|
||||
|
||||
<!-- Begin MailChimp Signup Form -->
|
||||
<link href="//cdn-images.mailchimp.com/embedcode/slim-081711.css" rel="stylesheet" type="text/css">
|
||||
<style type="text/css">
|
||||
#mc_embed_signup{background:#fff; clear:left; font:14px Helvetica,Arial,sans-serif; }
|
||||
/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
|
||||
We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
|
||||
</style>
|
||||
<div id="mc_embed_signup" style="background: rgb(245, 245, 245)">
|
||||
<form action="http://dabapps.us1.list-manage1.com/subscribe/post?u=cf73a9994eb5b8d8d461b5dfb&id=cb6af8e8bd" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>
|
||||
<!-- <label for="mce-EMAIL">Keep me posted!</label>
|
||||
--> <input style="width: 90%" type="email" value="" name="EMAIL" class="email" id="mce-EMAIL" placeholder="email address" required>
|
||||
<div class="clear"><input class="btn btn-success" type="submit" value="Yes, keep me posted!" name="subscribe" id="mc-embedded-subscribe" class="button"></div>
|
||||
</form>
|
||||
</div>
|
||||
</style></div>
|
||||
</ul>
|
||||
|
||||
|
||||
<!--End mc_embed_signup-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="main-content" class="span9">
|
||||
<p><a class="github" href="https://github.com/tomchristie/django-rest-framework/tree/master/rest_framework/parsers.py"><span class="label label-info">parsers.py</span></a></p>
|
||||
<h1 id="parsers">Parsers</h1>
|
||||
<blockquote>
|
||||
<p>Machine interacting web services tend to use more
|
||||
structured formats for sending data than form-encoded, since they're
|
||||
sending more complex data than simple forms</p>
|
||||
<p>— Malcom Tredinnick, <a href="https://groups.google.com/d/topic/django-developers/dxI4qVzrBY4/discussion">Django developers group</a></p>
|
||||
</blockquote>
|
||||
<p>REST framework includes a number of built in Parser classes, that allow you to accept requests with various media types. There is also support for defining your own custom parsers, which gives you the flexibility to design the media types that your API accepts.</p>
|
||||
<h2 id="how-the-parser-is-determined">How the parser is determined</h2>
|
||||
<p>The set of valid parsers for a view is always defined as a list of classes. When either <code>request.DATA</code> or <code>request.FILES</code> is accessed, REST framework will examine the <code>Content-Type</code> header on the incoming request, and determine which parser to use to parse the request content.</p>
|
||||
<hr />
|
||||
<p><strong>Note</strong>: When developing client applications always remember to make sure you're setting the <code>Content-Type</code> header when sending data in an HTTP request.</p>
|
||||
<p>If you don't set the content type, most clients will default to using <code>'application/x-www-form-urlencoded'</code>, which may not be what you wanted.</p>
|
||||
<p>As an example, if you are sending <code>json</code> encoded data using jQuery with the <a href="http://api.jquery.com/jQuery.ajax/">.ajax() method</a>, you should make sure to include the <code>contentType: 'application/json'</code> setting.</p>
|
||||
<hr />
|
||||
<h2 id="setting-the-parsers">Setting the parsers</h2>
|
||||
<p>The default set of parsers may be set globally, using the <code>DEFAULT_PARSER_CLASSES</code> setting. For example, the following settings would allow requests with <code>YAML</code> content.</p>
|
||||
<pre class="prettyprint lang-py"><code>REST_FRAMEWORK = {
|
||||
'DEFAULT_PARSER_CLASSES': (
|
||||
'rest_framework.parsers.YAMLParser',
|
||||
)
|
||||
}
|
||||
</code></pre>
|
||||
<p>You can also set the parsers used for an individual view, or viewset,
|
||||
using the <code>APIView</code> class based views.</p>
|
||||
<pre class="prettyprint lang-py"><code>from rest_framework.parsers import YAMLParser
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
|
||||
class ExampleView(APIView):
|
||||
"""
|
||||
A view that can accept POST requests with YAML content.
|
||||
"""
|
||||
parser_classes = (YAMLParser,)
|
||||
|
||||
def post(self, request, format=None):
|
||||
return Response({'received data': request.DATA})
|
||||
</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(['POST'])
|
||||
@parser_classes((YAMLParser,))
|
||||
def example_view(request, format=None):
|
||||
"""
|
||||
A view that can accept POST requests with YAML content.
|
||||
"""
|
||||
return Response({'received data': request.DATA})
|
||||
</code></pre>
|
||||
<hr />
|
||||
<h1 id="api-reference">API Reference</h1>
|
||||
<h2 id="jsonparser">JSONParser</h2>
|
||||
<p>Parses <code>JSON</code> request content.</p>
|
||||
<p><strong>.media_type</strong>: <code>application/json</code></p>
|
||||
<h2 id="yamlparser">YAMLParser</h2>
|
||||
<p>Parses <code>YAML</code> request content.</p>
|
||||
<p>Requires the <code>pyyaml</code> package to be installed.</p>
|
||||
<p><strong>.media_type</strong>: <code>application/yaml</code></p>
|
||||
<h2 id="xmlparser">XMLParser</h2>
|
||||
<p>Parses REST framework's default style of <code>XML</code> request content.</p>
|
||||
<p>Note that the <code>XML</code> markup language is typically used as the base language for more strictly defined domain-specific languages, such as <code>RSS</code>, <code>Atom</code>, and <code>XHTML</code>.</p>
|
||||
<p>If you are considering using <code>XML</code> for your API, you may want to consider implementing a custom renderer and parser for your specific requirements, and using an existing domain-specific media-type, or creating your own custom XML-based media-type.</p>
|
||||
<p>Requires the <code>defusedxml</code> package to be installed.</p>
|
||||
<p><strong>.media_type</strong>: <code>application/xml</code></p>
|
||||
<h2 id="formparser">FormParser</h2>
|
||||
<p>Parses HTML form content. <code>request.DATA</code> will be populated with a <code>QueryDict</code> of data, <code>request.FILES</code> will be populated with an empty <code>QueryDict</code> of data.</p>
|
||||
<p>You will typically want to use both <code>FormParser</code> and <code>MultiPartParser</code> together in order to fully support HTML form data.</p>
|
||||
<p><strong>.media_type</strong>: <code>application/x-www-form-urlencoded</code></p>
|
||||
<h2 id="multipartparser">MultiPartParser</h2>
|
||||
<p>Parses multipart HTML form content, which supports file uploads. Both <code>request.DATA</code> and <code>request.FILES</code> will be populated with a <code>QueryDict</code>.</p>
|
||||
<p>You will typically want to use both <code>FormParser</code> and <code>MultiPartParser</code> together in order to fully support HTML form data.</p>
|
||||
<p><strong>.media_type</strong>: <code>multipart/form-data</code></p>
|
||||
<h2 id="fileuploadparser">FileUploadParser</h2>
|
||||
<p>Parses raw file upload content. The <code>request.DATA</code> property will be an empty <code>QueryDict</code>, and <code>request.FILES</code> will be a dictionary with a single key <code>'file'</code> containing the uploaded file.</p>
|
||||
<p>If the view used with <code>FileUploadParser</code> is called with a <code>filename</code> URL keyword argument, then that argument will be used as the filename. If it is called without a <code>filename</code> URL keyword argument, then the client must set the filename in the <code>Content-Disposition</code> HTTP header. For example <code>Content-Disposition: attachment; filename=upload.jpg</code>.</p>
|
||||
<p><strong>.media_type</strong>: <code>*/*</code></p>
|
||||
<h5 id="notes">Notes:</h5>
|
||||
<ul>
|
||||
<li>The <code>FileUploadParser</code> is for usage with native clients that can upload the file as a raw data request. For web-based uploads, or for native clients with multipart upload support, you should use the <code>MultiPartParser</code> parser instead.</li>
|
||||
<li>Since this parser's <code>media_type</code> matches any content type, <code>FileUploadParser</code> should generally be the only parser set on an API view.</li>
|
||||
<li><code>FileUploadParser</code> respects Django's standard <code>FILE_UPLOAD_HANDLERS</code> setting, and the <code>request.upload_handlers</code> attribute. See the <a href="https://docs.djangoproject.com/en/dev/topics/http/file-uploads/#upload-handlers">Django documentation</a> for more details.</li>
|
||||
</ul>
|
||||
<h5 id="basic-usage-example">Basic usage example:</h5>
|
||||
<pre class="prettyprint lang-py"><code>class FileUploadView(views.APIView):
|
||||
parser_classes = (FileUploadParser,)
|
||||
|
||||
def put(self, request, filename, format=None):
|
||||
file_obj = request.FILES['file']
|
||||
# ...
|
||||
# do some staff with uploaded file
|
||||
# ...
|
||||
return Response(status=204)
|
||||
</code></pre>
|
||||
<hr />
|
||||
<h1 id="custom-parsers">Custom parsers</h1>
|
||||
<p>To implement a custom parser, you should override <code>BaseParser</code>, set the <code>.media_type</code> property, and implement the <code>.parse(self, stream, media_type, parser_context)</code> method.</p>
|
||||
<p>The method should return the data that will be used to populate the <code>request.DATA</code> property.</p>
|
||||
<p>The arguments passed to <code>.parse()</code> are:</p>
|
||||
<h3 id="stream">stream</h3>
|
||||
<p>A stream-like object representing the body of the request.</p>
|
||||
<h3 id="media_type">media_type</h3>
|
||||
<p>Optional. If provided, this is the media type of the incoming request content.</p>
|
||||
<p>Depending on the request's <code>Content-Type:</code> header, this may be more specific than the renderer's <code>media_type</code> attribute, and may include media type parameters. For example <code>"text/plain; charset=utf-8"</code>.</p>
|
||||
<h3 id="parser_context">parser_context</h3>
|
||||
<p>Optional. If supplied, this argument will be a dictionary containing any additional context that may be required to parse the request content.</p>
|
||||
<p>By default this will include the following keys: <code>view</code>, <code>request</code>, <code>args</code>, <code>kwargs</code>.</p>
|
||||
<h2 id="example">Example</h2>
|
||||
<p>The following is an example plaintext parser that will populate the <code>request.DATA</code> property with a string representing the body of the request. </p>
|
||||
<pre class="prettyprint lang-py"><code>class PlainTextParser(BaseParser):
|
||||
"""
|
||||
Plain text parser.
|
||||
"""
|
||||
|
||||
media_type = 'text/plain'
|
||||
|
||||
def parse(self, stream, media_type=None, parser_context=None):
|
||||
"""
|
||||
Simply return a string representing the body of the request.
|
||||
"""
|
||||
return stream.read()
|
||||
</code></pre>
|
||||
<hr />
|
||||
<h1 id="third-party-packages">Third party packages</h1>
|
||||
<p>The following third party packages are also available.</p>
|
||||
<h2 id="messagepack">MessagePack</h2>
|
||||
<p><a href="https://github.com/juanriaza/django-rest-framework-msgpack">MessagePack</a> is a fast, efficient binary serialization format. <a href="https://github.com/juanriaza">Juan Riaza</a> maintains the <a href="https://github.com/juanriaza/django-rest-framework-msgpack">djangorestframework-msgpack</a> package which provides MessagePack renderer and parser support for REST framework.</p>
|
||||
</div><!--/span-->
|
||||
</div><!--/row-->
|
||||
</div><!--/.fluid-container-->
|
||||
</div><!--/.body content-->
|
||||
|
||||
<div id="push"></div>
|
||||
</div><!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a></p>
|
||||
</footer>
|
||||
|
||||
<!-- Le javascript
|
||||
================================================== -->
|
||||
<!-- Placed at the end of the document so the pages load faster -->
|
||||
<script src="http://django-rest-framework.org/js/jquery-1.8.1-min.js"></script>
|
||||
<script src="http://django-rest-framework.org/js/prettify-1.0.js"></script>
|
||||
<script src="http://django-rest-framework.org/js/bootstrap-2.1.1-min.js"></script>
|
||||
<script>
|
||||
//$('.side-nav').scrollspy()
|
||||
var shiftWindow = function() { scrollBy(0, -50) };
|
||||
if (location.hash) shiftWindow();
|
||||
window.addEventListener("hashchange", shiftWindow);
|
||||
|
||||
$('.dropdown-menu').on('click touchstart', function(event) {
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
// Dynamically force sidenav to no higher than browser window
|
||||
$('.side-nav').css('max-height', window.innerHeight - 130);
|
||||
|
||||
$(function(){
|
||||
$(window).resize(function(){
|
||||
$('.side-nav').css('max-height', window.innerHeight - 130);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body></html>
|
||||
419
api-guide/permissions.html
Normal file
419
api-guide/permissions.html
Normal file
|
|
@ -0,0 +1,419 @@
|
|||
<!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 - Permissions</title>
|
||||
<link href="http://django-rest-framework.org/img/favicon.ico" rel="icon" type="image/x-icon">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Django, API, REST, Permissions, API Reference, Custom permissions, Third party packages">
|
||||
<meta name="author" content="Tom Christie">
|
||||
|
||||
<!-- Le styles -->
|
||||
<link href="http://django-rest-framework.org/css/prettify.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/bootstrap.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/bootstrap-responsive.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/default.css" rel="stylesheet">
|
||||
|
||||
<!-- 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]-->
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-18852272-2']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="prettyPrint()" class="permissions-page">
|
||||
|
||||
<div class="wrapper">
|
||||
|
||||
<div class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container-fluid">
|
||||
<a class="repo-link btn btn-primary btn-small" href="https://github.com/tomchristie/django-rest-framework/tree/master">GitHub</a>
|
||||
<a class="repo-link btn btn-inverse btn-small " href="../api-guide/throttling.html">Next <i class="icon-arrow-right icon-white"></i></a>
|
||||
<a class="repo-link btn btn-inverse btn-small " href="../api-guide/authentication.html"><i class="icon-arrow-left icon-white"></i> Previous</a>
|
||||
<a class="repo-link btn btn-inverse btn-small" href="#searchModal" data-toggle="modal"><i class="icon-search icon-white"></i> Search</a>
|
||||
<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>
|
||||
<a class="brand" href="http://django-rest-framework.org">Django REST framework</a>
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav">
|
||||
<li><a href="http://django-rest-framework.org">Home</a></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Tutorial <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/tutorial/quickstart.html">Quickstart</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/1-serialization.html">1 - Serialization</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/2-requests-and-responses.html">2 - Requests and responses</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/3-class-based-views.html">3 - Class based views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/4-authentication-and-permissions.html">4 - Authentication and permissions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/5-relationships-and-hyperlinked-apis.html">5 - Relationships and hyperlinked APIs</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/6-viewsets-and-routers.html">6 - Viewsets and routers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">API Guide <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/api-guide/requests.html">Requests</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/responses.html">Responses</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/views.html">Views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/generic-views.html">Generic views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/viewsets.html">Viewsets</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/routers.html">Routers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/parsers.html">Parsers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/renderers.html">Renderers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/serializers.html">Serializers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/fields.html">Serializer fields</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/relations.html">Serializer relations</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/authentication.html">Authentication</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/permissions.html">Permissions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/throttling.html">Throttling</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/filtering.html">Filtering</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/pagination.html">Pagination</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/content-negotiation.html">Content negotiation</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/format-suffixes.html">Format suffixes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/reverse.html">Returning URLs</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/exceptions.html">Exceptions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/status-codes.html">Status codes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/testing.html">Testing</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/settings.html">Settings</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Topics <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/topics/documenting-your-api.html">Documenting your API</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/ajax-csrf-cors.html">AJAX, CSRF & CORS</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/browser-enhancements.html">Browser enhancements</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/browsable-api.html">The Browsable API</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/rest-hypermedia-hateoas.html">REST, Hypermedia & HATEOAS</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/rest-framework-2-announcement.html">2.0 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/2.2-announcement.html">2.2 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/2.3-announcement.html">2.3 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/release-notes.html">Release Notes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/credits.html">Credits</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="nav pull-right">
|
||||
<!-- TODO
|
||||
<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>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="body-content">
|
||||
<div class="container-fluid">
|
||||
|
||||
<!-- Search Modal -->
|
||||
<div id="searchModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3 id="myModalLabel">Documentation search</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<!-- Custom google search -->
|
||||
<script>
|
||||
(function() {
|
||||
var cx = '015016005043623903336:rxraeohqk6w';
|
||||
var gcse = document.createElement('script');
|
||||
gcse.type = 'text/javascript';
|
||||
gcse.async = true;
|
||||
gcse.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') +
|
||||
'//www.google.com/cse/cse.js?cx=' + cx;
|
||||
var s = document.getElementsByTagName('script')[0];
|
||||
s.parentNode.insertBefore(gcse, s);
|
||||
})();
|
||||
</script>
|
||||
<gcse:search></gcse:search>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row-fluid">
|
||||
|
||||
<div class="span3">
|
||||
<!-- TODO
|
||||
<p style="margin-top: -12px">
|
||||
<a class="btn btn-mini btn-primary" style="width: 60px">« previous</a>
|
||||
<a class="btn btn-mini btn-primary" style="float: right; margin-right: 8px; width: 60px;">next »</a>
|
||||
</p>
|
||||
-->
|
||||
<div id="table-of-contents">
|
||||
<ul class="nav nav-list side-nav well sidebar-nav-fixed">
|
||||
<li class="main"><a href="#permissions">Permissions</a></li>
|
||||
<li><a href="#how-permissions-are-determined">How permissions are determined</a></li>
|
||||
<li><a href="#object-level-permissions">Object level permissions</a></li>
|
||||
<li><a href="#setting-the-permission-policy">Setting the permission policy</a></li>
|
||||
<li class="main"><a href="#api-reference">API Reference</a></li>
|
||||
<li><a href="#allowany">AllowAny</a></li>
|
||||
<li><a href="#isauthenticated">IsAuthenticated</a></li>
|
||||
<li><a href="#isadminuser">IsAdminUser</a></li>
|
||||
<li><a href="#isauthenticatedorreadonly">IsAuthenticatedOrReadOnly</a></li>
|
||||
<li><a href="#djangomodelpermissions">DjangoModelPermissions</a></li>
|
||||
<li><a href="#djangomodelpermissionsoranonreadonly">DjangoModelPermissionsOrAnonReadOnly</a></li>
|
||||
<li><a href="#tokenhasreadwritescope">TokenHasReadWriteScope</a></li>
|
||||
<li class="main"><a href="#custom-permissions">Custom permissions</a></li>
|
||||
<li><a href="#examples">Examples</a></li>
|
||||
<li class="main"><a href="#third-party-packages">Third party packages</a></li>
|
||||
<li><a href="#drf-any-permissions">DRF Any Permissions</a></li>
|
||||
<li><a href="#composed-permissions">Composed Permissions</a></li>
|
||||
|
||||
<div>
|
||||
<hr>
|
||||
|
||||
<p><strong>The team behind REST framework are launching a new API service.</strong></p>
|
||||
|
||||
<p>If you want to be first in line when we start issuing invitations, please sign up here:</p>
|
||||
|
||||
<!-- Begin MailChimp Signup Form -->
|
||||
<link href="//cdn-images.mailchimp.com/embedcode/slim-081711.css" rel="stylesheet" type="text/css">
|
||||
<style type="text/css">
|
||||
#mc_embed_signup{background:#fff; clear:left; font:14px Helvetica,Arial,sans-serif; }
|
||||
/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
|
||||
We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
|
||||
</style>
|
||||
<div id="mc_embed_signup" style="background: rgb(245, 245, 245)">
|
||||
<form action="http://dabapps.us1.list-manage1.com/subscribe/post?u=cf73a9994eb5b8d8d461b5dfb&id=cb6af8e8bd" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>
|
||||
<!-- <label for="mce-EMAIL">Keep me posted!</label>
|
||||
--> <input style="width: 90%" type="email" value="" name="EMAIL" class="email" id="mce-EMAIL" placeholder="email address" required>
|
||||
<div class="clear"><input class="btn btn-success" type="submit" value="Yes, keep me posted!" name="subscribe" id="mc-embedded-subscribe" class="button"></div>
|
||||
</form>
|
||||
</div>
|
||||
</style></div>
|
||||
</ul>
|
||||
|
||||
|
||||
<!--End mc_embed_signup-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="main-content" class="span9">
|
||||
<p><a class="github" href="https://github.com/tomchristie/django-rest-framework/tree/master/rest_framework/permissions.py"><span class="label label-info">permissions.py</span></a></p>
|
||||
<h1 id="permissions">Permissions</h1>
|
||||
<blockquote>
|
||||
<p>Authentication or identification by itself is not usually sufficient to gain access to information or code. For that, the entity requesting access must have authorization.</p>
|
||||
<p>— <a href="https://developer.apple.com/library/mac/#documentation/security/Conceptual/AuthenticationAndAuthorizationGuide/Authorization/Authorization.html">Apple Developer Documentation</a></p>
|
||||
</blockquote>
|
||||
<p>Together with <a href="authentication.html">authentication</a> and <a href="throttling.html">throttling</a>, permissions determine whether a request should be granted or denied access.</p>
|
||||
<p>Permission checks are always run at the very start of the view, before any other code is allowed to proceed. Permission checks will typically use the authentication information in the <code>request.user</code> and <code>request.auth</code> properties to determine if the incoming request should be permitted.</p>
|
||||
<h2 id="how-permissions-are-determined">How permissions are determined</h2>
|
||||
<p>Permissions in REST framework are always defined as a list of permission classes. </p>
|
||||
<p>Before running the main body of the view each permission in the list is checked.
|
||||
If any permission check fails an <code>exceptions.PermissionDenied</code> exception will be raised, and the main body of the view will not run.</p>
|
||||
<h2 id="object-level-permissions">Object level permissions</h2>
|
||||
<p>REST framework permissions also support object-level permissioning. Object level permissions are used to determine if a user should be allowed to act on a particular object, which will typically be a model instance.</p>
|
||||
<p>Object level permissions are run by REST framework's generic views when <code>.get_object()</code> is called.
|
||||
As with view level permissions, an <code>exceptions.PermissionDenied</code> exception will be raised if the user is not allowed to act on the given object.</p>
|
||||
<p>If you're writing your own views and want to enforce object level permissions,
|
||||
or if you override the <code>get_object</code> method on a generic view, then you'll need to explicitly call the <code>.check_object_permissions(request, obj)</code> method on the view at the point at which you've retrieved the object.</p>
|
||||
<p>This will either raise a <code>PermissionDenied</code> or <code>NotAuthenticated</code> exception, or simply return if the view has the appropriate permissions.</p>
|
||||
<p>For example:</p>
|
||||
<pre class="prettyprint lang-py"><code>def get_object(self):
|
||||
obj = get_object_or_404(self.get_queryset())
|
||||
self.check_object_permissions(self.request, obj)
|
||||
return obj
|
||||
</code></pre>
|
||||
<h2 id="setting-the-permission-policy">Setting the permission policy</h2>
|
||||
<p>The default permission policy may be set globally, using the <code>DEFAULT_PERMISSION_CLASSES</code> setting. For example.</p>
|
||||
<pre class="prettyprint lang-py"><code>REST_FRAMEWORK = {
|
||||
'DEFAULT_PERMISSION_CLASSES': (
|
||||
'rest_framework.permissions.IsAuthenticated',
|
||||
)
|
||||
}
|
||||
</code></pre>
|
||||
<p>If not specified, this setting defaults to allowing unrestricted access:</p>
|
||||
<pre class="prettyprint lang-py"><code>'DEFAULT_PERMISSION_CLASSES': (
|
||||
'rest_framework.permissions.AllowAny',
|
||||
)
|
||||
</code></pre>
|
||||
<p>You can also set the authentication policy on a per-view, or per-viewset basis,
|
||||
using the <code>APIView</code> class based views.</p>
|
||||
<pre class="prettyprint lang-py"><code>from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.responses import Response
|
||||
from rest_framework.views import APIView
|
||||
|
||||
class ExampleView(APIView):
|
||||
permission_classes = (IsAuthenticated,)
|
||||
|
||||
def get(self, request, format=None):
|
||||
content = {
|
||||
'status': 'request was permitted'
|
||||
}
|
||||
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')
|
||||
@permission_classes((IsAuthenticated, ))
|
||||
def example_view(request, format=None):
|
||||
content = {
|
||||
'status': 'request was permitted'
|
||||
}
|
||||
return Response(content)
|
||||
</code></pre>
|
||||
<hr />
|
||||
<h1 id="api-reference">API Reference</h1>
|
||||
<h2 id="allowany">AllowAny</h2>
|
||||
<p>The <code>AllowAny</code> permission class will allow unrestricted access, <strong>regardless of if the request was authenticated or unauthenticated</strong>.</p>
|
||||
<p>This permission is not strictly required, since you can achieve the same result by using an empty list or tuple for the permissions setting, but you may find it useful to specify this class because it makes the intention explicit.</p>
|
||||
<h2 id="isauthenticated">IsAuthenticated</h2>
|
||||
<p>The <code>IsAuthenticated</code> permission class will deny permission to any unauthenticated user, and allow permission otherwise.</p>
|
||||
<p>This permission is suitable if you want your API to only be accessible to registered users.</p>
|
||||
<h2 id="isadminuser">IsAdminUser</h2>
|
||||
<p>The <code>IsAdminUser</code> permission class will deny permission to any user, unless <code>user.is_staff</code> is <code>True</code> in which case permission will be allowed.</p>
|
||||
<p>This permission is suitable is you want your API to only be accessible to a subset of trusted administrators.</p>
|
||||
<h2 id="isauthenticatedorreadonly">IsAuthenticatedOrReadOnly</h2>
|
||||
<p>The <code>IsAuthenticatedOrReadOnly</code> will allow authenticated users to perform any request. Requests for unauthorised users will only be permitted if the request method is one of the "safe" methods; <code>GET</code>, <code>HEAD</code> or <code>OPTIONS</code>.</p>
|
||||
<p>This permission is suitable if you want to your API to allow read permissions to anonymous users, and only allow write permissions to authenticated users.</p>
|
||||
<h2 id="djangomodelpermissions">DjangoModelPermissions</h2>
|
||||
<p>This permission class ties into Django's standard <code>django.contrib.auth</code> <a href="https://docs.djangoproject.com/en/1.0/topics/auth/#permissions">model permissions</a>. When applied to a view that has a <code>.model</code> property, authorization will only be granted if the user <em>is authenticated</em> and has the <em>relevant model permissions</em> assigned.</p>
|
||||
<ul>
|
||||
<li><code>POST</code> requests require the user to have the <code>add</code> permission on the model.</li>
|
||||
<li><code>PUT</code> and <code>PATCH</code> requests require the user to have the <code>change</code> permission on the model.</li>
|
||||
<li><code>DELETE</code> requests require the user to have the <code>delete</code> permission on the model.</li>
|
||||
</ul>
|
||||
<p>The default behaviour can also be overridden to support custom model permissions. For example, you might want to include a <code>view</code> model permission for <code>GET</code> requests.</p>
|
||||
<p>To use custom model permissions, override <code>DjangoModelPermissions</code> and set the <code>.perms_map</code> property. Refer to the source code for details.</p>
|
||||
<h2 id="djangomodelpermissionsoranonreadonly">DjangoModelPermissionsOrAnonReadOnly</h2>
|
||||
<p>Similar to <code>DjangoModelPermissions</code>, but also allows unauthenticated users to have read-only access to the API.</p>
|
||||
<h2 id="djangoobjectpermissions">DjangoObjectPermissions</h2>
|
||||
<p>This permission class ties into Django's standard <a href="https://docs.djangoproject.com/en/dev/topics/auth/customizing/#handling-object-permissions">object permissions framework</a> that allows per-object permissions on models. In order to use this permission class, you'll also need to add a permission backend that supports object-level permissions, such as <a href="https://github.com/lukaszb/django-guardian">django-guardian</a>.</p>
|
||||
<p>When applied to a view that has a <code>.model</code> property, authorization will only be granted if the user <em>is authenticated</em> and has the <em>relevant per-object permissions</em> and <em>relevant model permissions</em> assigned.</p>
|
||||
<ul>
|
||||
<li><code>POST</code> requests require the user to have the <code>add</code> permission on the model instance.</li>
|
||||
<li><code>PUT</code> and <code>PATCH</code> requests require the user to have the <code>change</code> permission on the model instance.</li>
|
||||
<li><code>DELETE</code> requests require the user to have the <code>delete</code> permission on the model instance.</li>
|
||||
</ul>
|
||||
<p>Note that <code>DjangoObjectPermissions</code> <strong>does not</strong> require the <code>django-guardian</code> package, and should support other object-level backends equally well.</p>
|
||||
<p>As with <code>DjangoModelPermissions</code> you can use custom model permissions by overriding <code>DjangoModelPermissions</code> and setting the <code>.perms_map</code> property. Refer to the source code for details. Note that if you add a custom <code>view</code> permission for <code>GET</code>, <code>HEAD</code> and <code>OPTIONS</code> requests, you'll probably also want to consider adding the <code>DjangoObjectPermissionsFilter</code> class to ensure that list endpoints only return results including objects for which the user has appropriate view permissions.</p>
|
||||
<h2 id="tokenhasreadwritescope">TokenHasReadWriteScope</h2>
|
||||
<p>This permission class is intended for use with either of the <code>OAuthAuthentication</code> and <code>OAuth2Authentication</code> classes, and ties into the scoping that their backends provide.</p>
|
||||
<p>Requests with a safe methods of <code>GET</code>, <code>OPTIONS</code> or <code>HEAD</code> will be allowed if the authenticated token has read permission.</p>
|
||||
<p>Requests for <code>POST</code>, <code>PUT</code>, <code>PATCH</code> and <code>DELETE</code> will be allowed if the authenticated token has write permission.</p>
|
||||
<p>This permission class relies on the implementations of the <a href="http://code.larlet.fr/django-oauth-plus">django-oauth-plus</a> and <a href="https://github.com/caffeinehit/django-oauth2-provider">django-oauth2-provider</a> libraries, which both provide limited support for controlling the scope of access tokens:</p>
|
||||
<ul>
|
||||
<li><code>django-oauth-plus</code>: Tokens are associated with a <code>Resource</code> class which has a <code>name</code>, <code>url</code> and <code>is_readonly</code> properties.</li>
|
||||
<li><code>django-oauth2-provider</code>: Tokens are associated with a bitwise <code>scope</code> attribute, that defaults to providing bitwise values for <code>read</code> and/or <code>write</code>.</li>
|
||||
</ul>
|
||||
<p>If you require more advanced scoping for your API, such as restricting tokens to accessing a subset of functionality of your API then you will need to provide a custom permission class. See the source of the <code>django-oauth-plus</code> or <code>django-oauth2-provider</code> package for more details on scoping token access.</p>
|
||||
<hr />
|
||||
<h1 id="custom-permissions">Custom permissions</h1>
|
||||
<p>To implement a custom permission, override <code>BasePermission</code> and implement either, or both, of the following methods:</p>
|
||||
<ul>
|
||||
<li><code>.has_permission(self, request, view)</code></li>
|
||||
<li><code>.has_object_permission(self, request, view, obj)</code></li>
|
||||
</ul>
|
||||
<p>The methods should return <code>True</code> if the request should be granted access, and <code>False</code> otherwise.</p>
|
||||
<p>If you need to test if a request is a read operation or a write operation, you should check the request method against the constant <code>SAFE_METHODS</code>, which is a tuple containing <code>'GET'</code>, <code>'OPTIONS'</code> and <code>'HEAD'</code>. For example:</p>
|
||||
<pre class="prettyprint lang-py"><code>if request.method in permissions.SAFE_METHODS:
|
||||
# Check permissions for read-only request
|
||||
else:
|
||||
# Check permissions for write request
|
||||
</code></pre>
|
||||
<hr />
|
||||
<p><strong>Note</strong>: In versions 2.0 and 2.1, the signature for the permission checks always included an optional <code>obj</code> parameter, like so: <code>.has_permission(self, request, view, obj=None)</code>. The method would be called twice, first for the global permission checks, with no object supplied, and second for the object-level check when required.</p>
|
||||
<p>As of version 2.2 this signature has now been replaced with two separate method calls, which is more explicit and obvious. The old style signature continues to work, but its use will result in a <code>PendingDeprecationWarning</code>, which is silent by default. In 2.3 this will be escalated to a <code>DeprecationWarning</code>, and in 2.4 the old-style signature will be removed.</p>
|
||||
<p>For more details see the <a href="../topics/2.2-announcement.html">2.2 release announcement</a>.</p>
|
||||
<hr />
|
||||
<h2 id="examples">Examples</h2>
|
||||
<p>The following is an example of a permission class that checks the incoming request's IP address against a blacklist, and denies the request if the IP has been blacklisted.</p>
|
||||
<pre class="prettyprint lang-py"><code>from rest_framework import permissions
|
||||
|
||||
class BlacklistPermission(permissions.BasePermission):
|
||||
"""
|
||||
Global permission check for blacklisted IPs.
|
||||
"""
|
||||
|
||||
def has_permission(self, request, view):
|
||||
ip_addr = request.META['REMOTE_ADDR']
|
||||
blacklisted = Blacklist.objects.filter(ip_addr=ip_addr).exists()
|
||||
return not blacklisted
|
||||
</code></pre>
|
||||
<p>As well as global permissions, that are run against all incoming requests, you can also create object-level permissions, that are only run against operations that affect a particular object instance. For example:</p>
|
||||
<pre class="prettyprint lang-py"><code>class IsOwnerOrReadOnly(permissions.BasePermission):
|
||||
"""
|
||||
Object-level permission to only allow owners of an object to edit it.
|
||||
Assumes the model instance has an `owner` attribute.
|
||||
"""
|
||||
|
||||
def has_object_permission(self, request, view, obj):
|
||||
# Read permissions are allowed to any request,
|
||||
# so we'll always allow GET, HEAD or OPTIONS requests.
|
||||
if request.method in permissions.SAFE_METHODS:
|
||||
return True
|
||||
|
||||
# Instance must have an attribute named `owner`.
|
||||
return obj.owner == request.user
|
||||
</code></pre>
|
||||
<p>Note that the generic views will check the appropriate object level permissions, but if you're writing your own custom views, you'll need to make sure you check the object level permission checks yourself. You can do so by calling <code>self.check_object_permissions(request, obj)</code> from the view once you have the object instance. This call will raise an appropriate <code>APIException</code> if any object-level permission checks fail, and will otherwise simply return.</p>
|
||||
<p>Also note that the generic views will only check the object-level permissions for views that retrieve a single model instance. If you require object-level filtering of list views, you'll need to filter the queryset separately. See the <a href="filtering.html">filtering documentation</a> for more details.</p>
|
||||
<hr />
|
||||
<h1 id="third-party-packages">Third party packages</h1>
|
||||
<p>The following third party packages are also available.</p>
|
||||
<h2 id="drf-any-permissions">DRF Any Permissions</h2>
|
||||
<p>The <a href="https://github.com/kevin-brown/drf-any-permissions">DRF Any Permissions</a> packages provides a different permission behavior in contrast to REST framework. Instead of all specified permissions being required, only one of the given permissions has to be true in order to get access to the view.</p>
|
||||
<h2 id="composed-permissions">Composed Permissions</h2>
|
||||
<p>The <a href="https://github.com/niwibe/djangorestframework-composed-permissions">Composed Permissions</a> package provides a simple way to define complex and multi-depth (with logic operators) permission objects, using small and reusable components.</p>
|
||||
</div><!--/span-->
|
||||
</div><!--/row-->
|
||||
</div><!--/.fluid-container-->
|
||||
</div><!--/.body content-->
|
||||
|
||||
<div id="push"></div>
|
||||
</div><!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a></p>
|
||||
</footer>
|
||||
|
||||
<!-- Le javascript
|
||||
================================================== -->
|
||||
<!-- Placed at the end of the document so the pages load faster -->
|
||||
<script src="http://django-rest-framework.org/js/jquery-1.8.1-min.js"></script>
|
||||
<script src="http://django-rest-framework.org/js/prettify-1.0.js"></script>
|
||||
<script src="http://django-rest-framework.org/js/bootstrap-2.1.1-min.js"></script>
|
||||
<script>
|
||||
//$('.side-nav').scrollspy()
|
||||
var shiftWindow = function() { scrollBy(0, -50) };
|
||||
if (location.hash) shiftWindow();
|
||||
window.addEventListener("hashchange", shiftWindow);
|
||||
|
||||
$('.dropdown-menu').on('click touchstart', function(event) {
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
// Dynamically force sidenav to no higher than browser window
|
||||
$('.side-nav').css('max-height', window.innerHeight - 130);
|
||||
|
||||
$(function(){
|
||||
$(window).resize(function(){
|
||||
$('.side-nav').css('max-height', window.innerHeight - 130);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body></html>
|
||||
616
api-guide/relations.html
Normal file
616
api-guide/relations.html
Normal file
|
|
@ -0,0 +1,616 @@
|
|||
<!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 - Serializer relations</title>
|
||||
<link href="http://django-rest-framework.org/img/favicon.ico" rel="icon" type="image/x-icon">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Django, API, REST, Serializer relations, API Reference, Nested relationships, Custom relational fields, Further notes">
|
||||
<meta name="author" content="Tom Christie">
|
||||
|
||||
<!-- Le styles -->
|
||||
<link href="http://django-rest-framework.org/css/prettify.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/bootstrap.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/bootstrap-responsive.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/default.css" rel="stylesheet">
|
||||
|
||||
<!-- 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]-->
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-18852272-2']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="prettyPrint()" class="relations-page">
|
||||
|
||||
<div class="wrapper">
|
||||
|
||||
<div class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container-fluid">
|
||||
<a class="repo-link btn btn-primary btn-small" href="https://github.com/tomchristie/django-rest-framework/tree/master">GitHub</a>
|
||||
<a class="repo-link btn btn-inverse btn-small " href="../api-guide/authentication.html">Next <i class="icon-arrow-right icon-white"></i></a>
|
||||
<a class="repo-link btn btn-inverse btn-small " href="../api-guide/fields.html"><i class="icon-arrow-left icon-white"></i> Previous</a>
|
||||
<a class="repo-link btn btn-inverse btn-small" href="#searchModal" data-toggle="modal"><i class="icon-search icon-white"></i> Search</a>
|
||||
<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>
|
||||
<a class="brand" href="http://django-rest-framework.org">Django REST framework</a>
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav">
|
||||
<li><a href="http://django-rest-framework.org">Home</a></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Tutorial <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/tutorial/quickstart.html">Quickstart</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/1-serialization.html">1 - Serialization</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/2-requests-and-responses.html">2 - Requests and responses</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/3-class-based-views.html">3 - Class based views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/4-authentication-and-permissions.html">4 - Authentication and permissions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/5-relationships-and-hyperlinked-apis.html">5 - Relationships and hyperlinked APIs</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/6-viewsets-and-routers.html">6 - Viewsets and routers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">API Guide <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/api-guide/requests.html">Requests</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/responses.html">Responses</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/views.html">Views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/generic-views.html">Generic views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/viewsets.html">Viewsets</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/routers.html">Routers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/parsers.html">Parsers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/renderers.html">Renderers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/serializers.html">Serializers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/fields.html">Serializer fields</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/relations.html">Serializer relations</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/authentication.html">Authentication</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/permissions.html">Permissions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/throttling.html">Throttling</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/filtering.html">Filtering</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/pagination.html">Pagination</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/content-negotiation.html">Content negotiation</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/format-suffixes.html">Format suffixes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/reverse.html">Returning URLs</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/exceptions.html">Exceptions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/status-codes.html">Status codes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/testing.html">Testing</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/settings.html">Settings</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Topics <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/topics/documenting-your-api.html">Documenting your API</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/ajax-csrf-cors.html">AJAX, CSRF & CORS</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/browser-enhancements.html">Browser enhancements</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/browsable-api.html">The Browsable API</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/rest-hypermedia-hateoas.html">REST, Hypermedia & HATEOAS</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/rest-framework-2-announcement.html">2.0 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/2.2-announcement.html">2.2 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/2.3-announcement.html">2.3 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/release-notes.html">Release Notes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/credits.html">Credits</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="nav pull-right">
|
||||
<!-- TODO
|
||||
<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>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="body-content">
|
||||
<div class="container-fluid">
|
||||
|
||||
<!-- Search Modal -->
|
||||
<div id="searchModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3 id="myModalLabel">Documentation search</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<!-- Custom google search -->
|
||||
<script>
|
||||
(function() {
|
||||
var cx = '015016005043623903336:rxraeohqk6w';
|
||||
var gcse = document.createElement('script');
|
||||
gcse.type = 'text/javascript';
|
||||
gcse.async = true;
|
||||
gcse.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') +
|
||||
'//www.google.com/cse/cse.js?cx=' + cx;
|
||||
var s = document.getElementsByTagName('script')[0];
|
||||
s.parentNode.insertBefore(gcse, s);
|
||||
})();
|
||||
</script>
|
||||
<gcse:search></gcse:search>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row-fluid">
|
||||
|
||||
<div class="span3">
|
||||
<!-- TODO
|
||||
<p style="margin-top: -12px">
|
||||
<a class="btn btn-mini btn-primary" style="width: 60px">« previous</a>
|
||||
<a class="btn btn-mini btn-primary" style="float: right; margin-right: 8px; width: 60px;">next »</a>
|
||||
</p>
|
||||
-->
|
||||
<div id="table-of-contents">
|
||||
<ul class="nav nav-list side-nav well sidebar-nav-fixed">
|
||||
<li class="main"><a href="#serializer-relations">Serializer relations</a></li>
|
||||
<li class="main"><a href="#api-reference">API Reference</a></li>
|
||||
<li><a href="#relatedfield">RelatedField</a></li>
|
||||
<li><a href="#primarykeyrelatedfield">PrimaryKeyRelatedField</a></li>
|
||||
<li><a href="#hyperlinkedrelatedfield">HyperlinkedRelatedField</a></li>
|
||||
<li><a href="#slugrelatedfield">SlugRelatedField</a></li>
|
||||
<li><a href="#hyperlinkedidentityfield">HyperlinkedIdentityField</a></li>
|
||||
<li class="main"><a href="#nested-relationships">Nested relationships</a></li>
|
||||
<li><a href="#example">Example</a></li>
|
||||
<li class="main"><a href="#custom-relational-fields">Custom relational fields</a></li>
|
||||
<li><a href="#example">Example</a></li>
|
||||
<li class="main"><a href="#further-notes">Further notes</a></li>
|
||||
<li><a href="#reverse-relations">Reverse relations</a></li>
|
||||
<li><a href="#generic-relationships">Generic relationships</a></li>
|
||||
<li><a href="#manytomanyfields-with-a-through-model">ManyToManyFields with a Through Model</a></li>
|
||||
<li><a href="#advanced-hyperlinked-fields">Advanced Hyperlinked fields</a></li>
|
||||
<li><a href="#deprecated-apis">Deprecated APIs</a></li>
|
||||
|
||||
<div>
|
||||
<hr>
|
||||
|
||||
<p><strong>The team behind REST framework are launching a new API service.</strong></p>
|
||||
|
||||
<p>If you want to be first in line when we start issuing invitations, please sign up here:</p>
|
||||
|
||||
<!-- Begin MailChimp Signup Form -->
|
||||
<link href="//cdn-images.mailchimp.com/embedcode/slim-081711.css" rel="stylesheet" type="text/css">
|
||||
<style type="text/css">
|
||||
#mc_embed_signup{background:#fff; clear:left; font:14px Helvetica,Arial,sans-serif; }
|
||||
/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
|
||||
We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
|
||||
</style>
|
||||
<div id="mc_embed_signup" style="background: rgb(245, 245, 245)">
|
||||
<form action="http://dabapps.us1.list-manage1.com/subscribe/post?u=cf73a9994eb5b8d8d461b5dfb&id=cb6af8e8bd" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>
|
||||
<!-- <label for="mce-EMAIL">Keep me posted!</label>
|
||||
--> <input style="width: 90%" type="email" value="" name="EMAIL" class="email" id="mce-EMAIL" placeholder="email address" required>
|
||||
<div class="clear"><input class="btn btn-success" type="submit" value="Yes, keep me posted!" name="subscribe" id="mc-embedded-subscribe" class="button"></div>
|
||||
</form>
|
||||
</div>
|
||||
</style></div>
|
||||
</ul>
|
||||
|
||||
|
||||
<!--End mc_embed_signup-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="main-content" class="span9">
|
||||
<p><a class="github" href="https://github.com/tomchristie/django-rest-framework/tree/master/rest_framework/relations.py"><span class="label label-info">relations.py</span></a></p>
|
||||
<h1 id="serializer-relations">Serializer relations</h1>
|
||||
<blockquote>
|
||||
<p>Bad programmers worry about the code.
|
||||
Good programmers worry about data structures and their relationships.</p>
|
||||
<p>— <a href="http://lwn.net/Articles/193245/">Linus Torvalds</a></p>
|
||||
</blockquote>
|
||||
<p>Relational fields are used to represent model relationships. They can be applied to <code>ForeignKey</code>, <code>ManyToManyField</code> and <code>OneToOneField</code> relationships, as well as to reverse relationships, and custom relationships such as <code>GenericForeignKey</code>.</p>
|
||||
<hr />
|
||||
<p><strong>Note:</strong> The relational fields are declared in <code>relations.py</code>, but by convention you should import them from the <code>serializers</code> module, using <code>from rest_framework import serializers</code> and refer to fields as <code>serializers.<FieldName></code>.</p>
|
||||
<hr />
|
||||
<h1 id="api-reference">API Reference</h1>
|
||||
<p>In order to explain the various types of relational fields, we'll use a couple of simple models for our examples. Our models will be for music albums, and the tracks listed on each album.</p>
|
||||
<pre class="prettyprint lang-py"><code>class Album(models.Model):
|
||||
album_name = models.CharField(max_length=100)
|
||||
artist = models.CharField(max_length=100)
|
||||
|
||||
class Track(models.Model):
|
||||
album = models.ForeignKey(Album, related_name='tracks')
|
||||
order = models.IntegerField()
|
||||
title = models.CharField(max_length=100)
|
||||
duration = models.IntegerField()
|
||||
|
||||
class Meta:
|
||||
unique_together = ('album', 'order')
|
||||
order_by = 'order'
|
||||
|
||||
def __unicode__(self):
|
||||
return '%d: %s' % (self.order, self.title)
|
||||
</code></pre>
|
||||
<h2 id="relatedfield">RelatedField</h2>
|
||||
<p><code>RelatedField</code> may be used to represent the target of the relationship using its <code>__unicode__</code> method.</p>
|
||||
<p>For example, the following serializer.</p>
|
||||
<pre class="prettyprint lang-py"><code>class AlbumSerializer(serializers.ModelSerializer):
|
||||
tracks = RelatedField(many=True)
|
||||
|
||||
class Meta:
|
||||
model = Album
|
||||
fields = ('album_name', 'artist', 'tracks')
|
||||
</code></pre>
|
||||
<p>Would serialize to the following representation.</p>
|
||||
<pre class="prettyprint lang-py"><code>{
|
||||
'album_name': 'Things We Lost In The Fire',
|
||||
'artist': 'Low',
|
||||
'tracks': [
|
||||
'1: Sunflower',
|
||||
'2: Whitetail',
|
||||
'3: Dinosaur Act',
|
||||
...
|
||||
]
|
||||
}
|
||||
</code></pre>
|
||||
<p>This field is read only.</p>
|
||||
<p><strong>Arguments</strong>:</p>
|
||||
<ul>
|
||||
<li><code>many</code> - If applied to a to-many relationship, you should set this argument to <code>True</code>.</li>
|
||||
</ul>
|
||||
<h2 id="primarykeyrelatedfield">PrimaryKeyRelatedField</h2>
|
||||
<p><code>PrimaryKeyRelatedField</code> may be used to represent the target of the relationship using its primary key.</p>
|
||||
<p>For example, the following serializer:</p>
|
||||
<pre class="prettyprint lang-py"><code>class AlbumSerializer(serializers.ModelSerializer):
|
||||
tracks = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = Album
|
||||
fields = ('album_name', 'artist', 'tracks')
|
||||
</code></pre>
|
||||
<p>Would serialize to a representation like this:</p>
|
||||
<pre class="prettyprint lang-py"><code>{
|
||||
'album_name': 'The Roots',
|
||||
'artist': 'Undun',
|
||||
'tracks': [
|
||||
89,
|
||||
90,
|
||||
91,
|
||||
...
|
||||
]
|
||||
}
|
||||
</code></pre>
|
||||
<p>By default this field is read-write, although you can change this behavior using the <code>read_only</code> flag.</p>
|
||||
<p><strong>Arguments</strong>:</p>
|
||||
<ul>
|
||||
<li><code>many</code> - If applied to a to-many relationship, you should set this argument to <code>True</code>.</li>
|
||||
<li><code>required</code> - If set to <code>False</code>, the field will accept values of <code>None</code> or the empty-string for nullable relationships.</li>
|
||||
<li><code>queryset</code> - By default <code>ModelSerializer</code> classes will use the default queryset for the relationship. <code>Serializer</code> classes must either set a queryset explicitly, or set <code>read_only=True</code>.</li>
|
||||
</ul>
|
||||
<h2 id="hyperlinkedrelatedfield">HyperlinkedRelatedField</h2>
|
||||
<p><code>HyperlinkedRelatedField</code> may be used to represent the target of the relationship using a hyperlink.</p>
|
||||
<p>For example, the following serializer:</p>
|
||||
<pre class="prettyprint lang-py"><code>class AlbumSerializer(serializers.ModelSerializer):
|
||||
tracks = serializers.HyperlinkedRelatedField(many=True, read_only=True,
|
||||
view_name='track-detail')
|
||||
|
||||
class Meta:
|
||||
model = Album
|
||||
fields = ('album_name', 'artist', 'tracks')
|
||||
</code></pre>
|
||||
<p>Would serialize to a representation like this:</p>
|
||||
<pre class="prettyprint lang-py"><code>{
|
||||
'album_name': 'Graceland',
|
||||
'artist': 'Paul Simon',
|
||||
'tracks': [
|
||||
'http://www.example.com/api/tracks/45/',
|
||||
'http://www.example.com/api/tracks/46/',
|
||||
'http://www.example.com/api/tracks/47/',
|
||||
...
|
||||
]
|
||||
}
|
||||
</code></pre>
|
||||
<p>By default this field is read-write, although you can change this behavior using the <code>read_only</code> flag.</p>
|
||||
<p><strong>Arguments</strong>:</p>
|
||||
<ul>
|
||||
<li><code>view_name</code> - The view name that should be used as the target of the relationship. <strong>required</strong>.</li>
|
||||
<li><code>many</code> - If applied to a to-many relationship, you should set this argument to <code>True</code>.</li>
|
||||
<li><code>required</code> - If set to <code>False</code>, the field will accept values of <code>None</code> or the empty-string for nullable relationships.</li>
|
||||
<li><code>queryset</code> - By default <code>ModelSerializer</code> classes will use the default queryset for the relationship. <code>Serializer</code> classes must either set a queryset explicitly, or set <code>read_only=True</code>.</li>
|
||||
<li><code>lookup_field</code> - The field on the target that should be used for the lookup. Should correspond to a URL keyword argument on the referenced view. Default is <code>'pk'</code>.</li>
|
||||
<li><code>format</code> - If using format suffixes, hyperlinked fields will use the same format suffix for the target unless overridden by using the <code>format</code> argument.</li>
|
||||
</ul>
|
||||
<h2 id="slugrelatedfield">SlugRelatedField</h2>
|
||||
<p><code>SlugRelatedField</code> may be used to represent the target of the relationship using a field on the target.</p>
|
||||
<p>For example, the following serializer:</p>
|
||||
<pre class="prettyprint lang-py"><code>class AlbumSerializer(serializers.ModelSerializer):
|
||||
tracks = serializers.SlugRelatedField(many=True, read_only=True,
|
||||
slug_field='title')
|
||||
|
||||
class Meta:
|
||||
model = Album
|
||||
fields = ('album_name', 'artist', 'tracks')
|
||||
</code></pre>
|
||||
<p>Would serialize to a representation like this:</p>
|
||||
<pre class="prettyprint lang-py"><code>{
|
||||
'album_name': 'Dear John',
|
||||
'artist': 'Loney Dear',
|
||||
'tracks': [
|
||||
'Airport Surroundings',
|
||||
'Everything Turns to You',
|
||||
'I Was Only Going Out',
|
||||
...
|
||||
]
|
||||
}
|
||||
</code></pre>
|
||||
<p>By default this field is read-write, although you can change this behavior using the <code>read_only</code> flag.</p>
|
||||
<p>When using <code>SlugRelatedField</code> as a read-write field, you will normally want to ensure that the slug field corresponds to a model field with <code>unique=True</code>.</p>
|
||||
<p><strong>Arguments</strong>:</p>
|
||||
<ul>
|
||||
<li><code>slug_field</code> - The field on the target that should be used to represent it. This should be a field that uniquely identifies any given instance. For example, <code>username</code>. <strong>required</strong></li>
|
||||
<li><code>many</code> - If applied to a to-many relationship, you should set this argument to <code>True</code>.</li>
|
||||
<li><code>required</code> - If set to <code>False</code>, the field will accept values of <code>None</code> or the empty-string for nullable relationships.</li>
|
||||
<li><code>queryset</code> - By default <code>ModelSerializer</code> classes will use the default queryset for the relationship. <code>Serializer</code> classes must either set a queryset explicitly, or set <code>read_only=True</code>.</li>
|
||||
</ul>
|
||||
<h2 id="hyperlinkedidentityfield">HyperlinkedIdentityField</h2>
|
||||
<p>This field can be applied as an identity relationship, such as the <code>'url'</code> field on a HyperlinkedModelSerializer. It can also be used for an attribute on the object. For example, the following serializer:</p>
|
||||
<pre class="prettyprint lang-py"><code>class AlbumSerializer(serializers.HyperlinkedModelSerializer):
|
||||
track_listing = serializers.HyperlinkedIdentityField(view_name='track-list')
|
||||
|
||||
class Meta:
|
||||
model = Album
|
||||
fields = ('album_name', 'artist', 'track_listing')
|
||||
</code></pre>
|
||||
<p>Would serialize to a representation like this:</p>
|
||||
<pre class="prettyprint lang-py"><code>{
|
||||
'album_name': 'The Eraser',
|
||||
'artist': 'Thom Yorke',
|
||||
'track_listing': 'http://www.example.com/api/track_list/12/',
|
||||
}
|
||||
</code></pre>
|
||||
<p>This field is always read-only.</p>
|
||||
<p><strong>Arguments</strong>:</p>
|
||||
<ul>
|
||||
<li><code>view_name</code> - The view name that should be used as the target of the relationship. <strong>required</strong>.</li>
|
||||
<li><code>lookup_field</code> - The field on the target that should be used for the lookup. Should correspond to a URL keyword argument on the referenced view. Default is <code>'pk'</code>.</li>
|
||||
<li><code>format</code> - If using format suffixes, hyperlinked fields will use the same format suffix for the target unless overridden by using the <code>format</code> argument.</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h1 id="nested-relationships">Nested relationships</h1>
|
||||
<p>Nested relationships can be expressed by using serializers as fields.</p>
|
||||
<p>If the field is used to represent a to-many relationship, you should add the <code>many=True</code> flag to the serializer field.</p>
|
||||
<h2 id="example">Example</h2>
|
||||
<p>For example, the following serializer:</p>
|
||||
<pre class="prettyprint lang-py"><code>class TrackSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Track
|
||||
fields = ('order', 'title')
|
||||
|
||||
class AlbumSerializer(serializers.ModelSerializer):
|
||||
tracks = TrackSerializer(many=True)
|
||||
|
||||
class Meta:
|
||||
model = Album
|
||||
fields = ('album_name', 'artist', 'tracks')
|
||||
</code></pre>
|
||||
<p>Would serialize to a nested representation like this:</p>
|
||||
<pre class="prettyprint lang-py"><code>{
|
||||
'album_name': 'The Grey Album',
|
||||
'artist': 'Danger Mouse',
|
||||
'tracks': [
|
||||
{'order': 1, 'title': 'Public Service Announcement'},
|
||||
{'order': 2, 'title': 'What More Can I Say'},
|
||||
{'order': 3, 'title': 'Encore'},
|
||||
...
|
||||
],
|
||||
}
|
||||
</code></pre>
|
||||
<h1 id="custom-relational-fields">Custom relational fields</h1>
|
||||
<p>To implement a custom relational field, you should override <code>RelatedField</code>, and implement the <code>.to_native(self, value)</code> method. This method takes the target of the field as the <code>value</code> argument, and should return the representation that should be used to serialize the target.</p>
|
||||
<p>If you want to implement a read-write relational field, you must also implement the <code>.from_native(self, data)</code> method, and add <code>read_only = False</code> to the class definition.</p>
|
||||
<h2 id="example_1">Example</h2>
|
||||
<p>For, example, we could define a relational field, to serialize a track to a custom string representation, using its ordering, title, and duration.</p>
|
||||
<pre class="prettyprint lang-py"><code>import time
|
||||
|
||||
class TrackListingField(serializers.RelatedField):
|
||||
def to_native(self, value):
|
||||
duration = time.strftime('%M:%S', time.gmtime(value.duration))
|
||||
return 'Track %d: %s (%s)' % (value.order, value.name, duration)
|
||||
|
||||
class AlbumSerializer(serializers.ModelSerializer):
|
||||
tracks = TrackListingField(many=True)
|
||||
|
||||
class Meta:
|
||||
model = Album
|
||||
fields = ('album_name', 'artist', 'tracks')
|
||||
</code></pre>
|
||||
<p>This custom field would then serialize to the following representation.</p>
|
||||
<pre class="prettyprint lang-py"><code>{
|
||||
'album_name': 'Sometimes I Wish We Were an Eagle',
|
||||
'artist': 'Bill Callahan',
|
||||
'tracks': [
|
||||
'Track 1: Jim Cain (04:39)',
|
||||
'Track 2: Eid Ma Clack Shaw (04:19)',
|
||||
'Track 3: The Wind and the Dove (04:34)',
|
||||
...
|
||||
]
|
||||
}
|
||||
</code></pre>
|
||||
<hr />
|
||||
<h1 id="further-notes">Further notes</h1>
|
||||
<h2 id="reverse-relations">Reverse relations</h2>
|
||||
<p>Note that reverse relationships are not automatically included by the <code>ModelSerializer</code> and <code>HyperlinkedModelSerializer</code> classes. To include a reverse relationship, you must explicitly add it to the fields list. For example:</p>
|
||||
<pre class="prettyprint lang-py"><code>class AlbumSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
fields = ('tracks', ...)
|
||||
</code></pre>
|
||||
<p>You'll normally want to ensure that you've set an appropriate <code>related_name</code> argument on the relationship, that you can use as the field name. For example:</p>
|
||||
<pre class="prettyprint lang-py"><code>class Track(models.Model):
|
||||
album = models.ForeignKey(Album, related_name='tracks')
|
||||
...
|
||||
</code></pre>
|
||||
<p>If you have not set a related name for the reverse relationship, you'll need to use the automatically generated related name in the <code>fields</code> argument. For example:</p>
|
||||
<pre class="prettyprint lang-py"><code>class AlbumSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
fields = ('track_set', ...)
|
||||
</code></pre>
|
||||
<p>See the Django documentation on <a href="https://docs.djangoproject.com/en/dev/topics/db/queries/#following-relationships-backward">reverse relationships</a> for more details.</p>
|
||||
<h2 id="generic-relationships">Generic relationships</h2>
|
||||
<p>If you want to serialize a generic foreign key, you need to define a custom field, to determine explicitly how you want serialize the targets of the relationship.</p>
|
||||
<p>For example, given the following model for a tag, which has a generic relationship with other arbitrary models:</p>
|
||||
<pre class="prettyprint lang-py"><code>class TaggedItem(models.Model):
|
||||
"""
|
||||
Tags arbitrary model instances using a generic relation.
|
||||
|
||||
See: https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/
|
||||
"""
|
||||
tag_name = models.SlugField()
|
||||
content_type = models.ForeignKey(ContentType)
|
||||
object_id = models.PositiveIntegerField()
|
||||
tagged_object = GenericForeignKey('content_type', 'object_id')
|
||||
|
||||
def __unicode__(self):
|
||||
return self.tag
|
||||
</code></pre>
|
||||
<p>And the following two models, which may be have associated tags:</p>
|
||||
<pre class="prettyprint lang-py"><code>class Bookmark(models.Model):
|
||||
"""
|
||||
A bookmark consists of a URL, and 0 or more descriptive tags.
|
||||
"""
|
||||
url = models.URLField()
|
||||
tags = GenericRelation(TaggedItem)
|
||||
|
||||
|
||||
class Note(models.Model):
|
||||
"""
|
||||
A note consists of some text, and 0 or more descriptive tags.
|
||||
"""
|
||||
text = models.CharField(max_length=1000)
|
||||
tags = GenericRelation(TaggedItem)
|
||||
</code></pre>
|
||||
<p>We could define a custom field that could be used to serialize tagged instances, using the type of each instance to determine how it should be serialized.</p>
|
||||
<pre class="prettyprint lang-py"><code>class TaggedObjectRelatedField(serializers.RelatedField):
|
||||
"""
|
||||
A custom field to use for the `tagged_object` generic relationship.
|
||||
"""
|
||||
|
||||
def to_native(self, value):
|
||||
"""
|
||||
Serialize tagged objects to a simple textual representation.
|
||||
"""
|
||||
if isinstance(value, Bookmark):
|
||||
return 'Bookmark: ' + value.url
|
||||
elif isinstance(value, Note):
|
||||
return 'Note: ' + value.text
|
||||
raise Exception('Unexpected type of tagged object')
|
||||
</code></pre>
|
||||
<p>If you need the target of the relationship to have a nested representation, you can use the required serializers inside the <code>.to_native()</code> method:</p>
|
||||
<pre class="prettyprint lang-py"><code> def to_native(self, value):
|
||||
"""
|
||||
Serialize bookmark instances using a bookmark serializer,
|
||||
and note instances using a note serializer.
|
||||
"""
|
||||
if isinstance(value, Bookmark):
|
||||
serializer = BookmarkSerializer(value)
|
||||
elif isinstance(value, Note):
|
||||
serializer = NoteSerializer(value)
|
||||
else:
|
||||
raise Exception('Unexpected type of tagged object')
|
||||
|
||||
return serializer.data
|
||||
</code></pre>
|
||||
<p>Note that reverse generic keys, expressed using the <code>GenericRelation</code> field, can be serialized using the regular relational field types, since the type of the target in the relationship is always known.</p>
|
||||
<p>For more information see <a href="https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/#id1">the Django documentation on generic relations</a>.</p>
|
||||
<h2 id="manytomanyfields-with-a-through-model">ManyToManyFields with a Through Model</h2>
|
||||
<p>By default, relational fields that target a <code>ManyToManyField</code> with a
|
||||
<code>through</code> model specified are set to read-only.</p>
|
||||
<p>If you explicitly specify a relational field pointing to a
|
||||
<code>ManyToManyField</code> with a through model, be sure to set <code>read_only</code>
|
||||
to <code>True</code>.</p>
|
||||
<h2 id="advanced-hyperlinked-fields">Advanced Hyperlinked fields</h2>
|
||||
<p>If you have very specific requirements for the style of your hyperlinked relationships you can override <code>HyperlinkedRelatedField</code>. </p>
|
||||
<p>There are two methods you'll need to override.</p>
|
||||
<h4 id="get_urlself-obj-view_name-request-format">get_url(self, obj, view_name, request, format)</h4>
|
||||
<p>This method should return the URL that corresponds to the given object.</p>
|
||||
<p>May raise a <code>NoReverseMatch</code> if the <code>view_name</code> and <code>lookup_field</code>
|
||||
attributes are not configured to correctly match the URL conf.</p>
|
||||
<h4 id="get_objectself-queryset-view_name-view_args-view_kwargs">get_object(self, queryset, view_name, view_args, view_kwargs)</h4>
|
||||
<p>This method should the object that corresponds to the matched URL conf arguments.</p>
|
||||
<p>May raise an <code>ObjectDoesNotExist</code> exception.</p>
|
||||
<h3 id="example_2">Example</h3>
|
||||
<p>For example, if all your object URLs used both a account and a slug in the the URL to reference the object, you might create a custom field like this: </p>
|
||||
<pre class="prettyprint lang-py"><code>class CustomHyperlinkedField(serializers.HyperlinkedRelatedField):
|
||||
def get_url(self, obj, view_name, request, format):
|
||||
kwargs = {'account': obj.account, 'slug': obj.slug}
|
||||
return reverse(view_name, kwargs=kwargs, request=request, format=format)
|
||||
|
||||
def get_object(self, queryset, view_name, view_args, view_kwargs):
|
||||
account = view_kwargs['account']
|
||||
slug = view_kwargs['slug']
|
||||
return queryset.get(account=account, slug=slug)
|
||||
</code></pre>
|
||||
<hr />
|
||||
<h2 id="deprecated-apis">Deprecated APIs</h2>
|
||||
<p>The following classes have been deprecated, in favor of the <code>many=<bool></code> syntax.
|
||||
They continue to function, but their usage will raise a <code>PendingDeprecationWarning</code>, which is silent by default.</p>
|
||||
<ul>
|
||||
<li><code>ManyRelatedField</code></li>
|
||||
<li><code>ManyPrimaryKeyRelatedField</code></li>
|
||||
<li><code>ManyHyperlinkedRelatedField</code></li>
|
||||
<li><code>ManySlugRelatedField</code></li>
|
||||
</ul>
|
||||
<p>The <code>null=<bool></code> flag has been deprecated in favor of the <code>required=<bool></code> flag. It will continue to function, but will raise a <code>PendingDeprecationWarning</code>.</p>
|
||||
<p>In the 2.3 release, these warnings will be escalated to a <code>DeprecationWarning</code>, which is loud by default.
|
||||
In the 2.4 release, these parts of the API will be removed entirely.</p>
|
||||
<p>For more details see the <a href="../topics/2.2-announcement.html">2.2 release announcement</a>.</p>
|
||||
</div><!--/span-->
|
||||
</div><!--/row-->
|
||||
</div><!--/.fluid-container-->
|
||||
</div><!--/.body content-->
|
||||
|
||||
<div id="push"></div>
|
||||
</div><!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a></p>
|
||||
</footer>
|
||||
|
||||
<!-- Le javascript
|
||||
================================================== -->
|
||||
<!-- Placed at the end of the document so the pages load faster -->
|
||||
<script src="http://django-rest-framework.org/js/jquery-1.8.1-min.js"></script>
|
||||
<script src="http://django-rest-framework.org/js/prettify-1.0.js"></script>
|
||||
<script src="http://django-rest-framework.org/js/bootstrap-2.1.1-min.js"></script>
|
||||
<script>
|
||||
//$('.side-nav').scrollspy()
|
||||
var shiftWindow = function() { scrollBy(0, -50) };
|
||||
if (location.hash) shiftWindow();
|
||||
window.addEventListener("hashchange", shiftWindow);
|
||||
|
||||
$('.dropdown-menu').on('click touchstart', function(event) {
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
// Dynamically force sidenav to no higher than browser window
|
||||
$('.side-nav').css('max-height', window.innerHeight - 130);
|
||||
|
||||
$(function(){
|
||||
$(window).resize(function(){
|
||||
$('.side-nav').css('max-height', window.innerHeight - 130);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body></html>
|
||||
543
api-guide/renderers.html
Normal file
543
api-guide/renderers.html
Normal file
|
|
@ -0,0 +1,543 @@
|
|||
<!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 - Renderers</title>
|
||||
<link href="http://django-rest-framework.org/img/favicon.ico" rel="icon" type="image/x-icon">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Django, API, REST, Renderers, API Reference, Custom renderers, Advanced renderer usage, Third party packages">
|
||||
<meta name="author" content="Tom Christie">
|
||||
|
||||
<!-- Le styles -->
|
||||
<link href="http://django-rest-framework.org/css/prettify.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/bootstrap.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/bootstrap-responsive.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/default.css" rel="stylesheet">
|
||||
|
||||
<!-- 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]-->
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-18852272-2']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="prettyPrint()" class="renderers-page">
|
||||
|
||||
<div class="wrapper">
|
||||
|
||||
<div class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container-fluid">
|
||||
<a class="repo-link btn btn-primary btn-small" href="https://github.com/tomchristie/django-rest-framework/tree/master">GitHub</a>
|
||||
<a class="repo-link btn btn-inverse btn-small " href="../api-guide/serializers.html">Next <i class="icon-arrow-right icon-white"></i></a>
|
||||
<a class="repo-link btn btn-inverse btn-small " href="../api-guide/parsers.html"><i class="icon-arrow-left icon-white"></i> Previous</a>
|
||||
<a class="repo-link btn btn-inverse btn-small" href="#searchModal" data-toggle="modal"><i class="icon-search icon-white"></i> Search</a>
|
||||
<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>
|
||||
<a class="brand" href="http://django-rest-framework.org">Django REST framework</a>
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav">
|
||||
<li><a href="http://django-rest-framework.org">Home</a></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Tutorial <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/tutorial/quickstart.html">Quickstart</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/1-serialization.html">1 - Serialization</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/2-requests-and-responses.html">2 - Requests and responses</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/3-class-based-views.html">3 - Class based views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/4-authentication-and-permissions.html">4 - Authentication and permissions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/5-relationships-and-hyperlinked-apis.html">5 - Relationships and hyperlinked APIs</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/6-viewsets-and-routers.html">6 - Viewsets and routers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">API Guide <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/api-guide/requests.html">Requests</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/responses.html">Responses</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/views.html">Views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/generic-views.html">Generic views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/viewsets.html">Viewsets</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/routers.html">Routers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/parsers.html">Parsers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/renderers.html">Renderers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/serializers.html">Serializers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/fields.html">Serializer fields</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/relations.html">Serializer relations</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/authentication.html">Authentication</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/permissions.html">Permissions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/throttling.html">Throttling</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/filtering.html">Filtering</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/pagination.html">Pagination</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/content-negotiation.html">Content negotiation</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/format-suffixes.html">Format suffixes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/reverse.html">Returning URLs</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/exceptions.html">Exceptions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/status-codes.html">Status codes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/testing.html">Testing</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/settings.html">Settings</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Topics <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/topics/documenting-your-api.html">Documenting your API</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/ajax-csrf-cors.html">AJAX, CSRF & CORS</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/browser-enhancements.html">Browser enhancements</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/browsable-api.html">The Browsable API</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/rest-hypermedia-hateoas.html">REST, Hypermedia & HATEOAS</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/rest-framework-2-announcement.html">2.0 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/2.2-announcement.html">2.2 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/2.3-announcement.html">2.3 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/release-notes.html">Release Notes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/credits.html">Credits</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="nav pull-right">
|
||||
<!-- TODO
|
||||
<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>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="body-content">
|
||||
<div class="container-fluid">
|
||||
|
||||
<!-- Search Modal -->
|
||||
<div id="searchModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3 id="myModalLabel">Documentation search</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<!-- Custom google search -->
|
||||
<script>
|
||||
(function() {
|
||||
var cx = '015016005043623903336:rxraeohqk6w';
|
||||
var gcse = document.createElement('script');
|
||||
gcse.type = 'text/javascript';
|
||||
gcse.async = true;
|
||||
gcse.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') +
|
||||
'//www.google.com/cse/cse.js?cx=' + cx;
|
||||
var s = document.getElementsByTagName('script')[0];
|
||||
s.parentNode.insertBefore(gcse, s);
|
||||
})();
|
||||
</script>
|
||||
<gcse:search></gcse:search>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row-fluid">
|
||||
|
||||
<div class="span3">
|
||||
<!-- TODO
|
||||
<p style="margin-top: -12px">
|
||||
<a class="btn btn-mini btn-primary" style="width: 60px">« previous</a>
|
||||
<a class="btn btn-mini btn-primary" style="float: right; margin-right: 8px; width: 60px;">next »</a>
|
||||
</p>
|
||||
-->
|
||||
<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>
|
||||
<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>
|
||||
<li class="main"><a href="#api-reference">API Reference</a></li>
|
||||
<li><a href="#jsonrenderer">JSONRenderer</a></li>
|
||||
<li><a href="#unicodejsonrenderer">UnicodeJSONRenderer</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="#templatehtmlrenderer">TemplateHTMLRenderer</a></li>
|
||||
<li><a href="#statichtmlrenderer">StaticHTMLRenderer</a></li>
|
||||
<li><a href="#htmlformrenderer">HTMLFormRenderer</a></li>
|
||||
<li><a href="#browsableapirenderer">BrowsableAPIRenderer</a></li>
|
||||
<li><a href="#multipartrenderer">MultiPartRenderer</a></li>
|
||||
<li class="main"><a href="#custom-renderers">Custom renderers</a></li>
|
||||
<li><a href="#example">Example</a></li>
|
||||
<li><a href="#setting-the-character-set">Setting the character set</a></li>
|
||||
<li class="main"><a href="#advanced-renderer-usage">Advanced renderer usage</a></li>
|
||||
<li><a href="#varying-behaviour-by-media-type">Varying behaviour by media type</a></li>
|
||||
<li><a href="#underspecifying-the-media-type">Underspecifying the media type</a></li>
|
||||
<li><a href="#designing-your-media-types">Designing your media types</a></li>
|
||||
<li><a href="#html-error-views">HTML error views</a></li>
|
||||
<li class="main"><a href="#third-party-packages">Third party packages</a></li>
|
||||
<li><a href="#messagepack">MessagePack</a></li>
|
||||
<li><a href="#csv">CSV</a></li>
|
||||
<li><a href="#ultrajson">UltraJSON</a></li>
|
||||
|
||||
<div>
|
||||
<hr>
|
||||
|
||||
<p><strong>The team behind REST framework are launching a new API service.</strong></p>
|
||||
|
||||
<p>If you want to be first in line when we start issuing invitations, please sign up here:</p>
|
||||
|
||||
<!-- Begin MailChimp Signup Form -->
|
||||
<link href="//cdn-images.mailchimp.com/embedcode/slim-081711.css" rel="stylesheet" type="text/css">
|
||||
<style type="text/css">
|
||||
#mc_embed_signup{background:#fff; clear:left; font:14px Helvetica,Arial,sans-serif; }
|
||||
/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
|
||||
We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
|
||||
</style>
|
||||
<div id="mc_embed_signup" style="background: rgb(245, 245, 245)">
|
||||
<form action="http://dabapps.us1.list-manage1.com/subscribe/post?u=cf73a9994eb5b8d8d461b5dfb&id=cb6af8e8bd" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>
|
||||
<!-- <label for="mce-EMAIL">Keep me posted!</label>
|
||||
--> <input style="width: 90%" type="email" value="" name="EMAIL" class="email" id="mce-EMAIL" placeholder="email address" required>
|
||||
<div class="clear"><input class="btn btn-success" type="submit" value="Yes, keep me posted!" name="subscribe" id="mc-embedded-subscribe" class="button"></div>
|
||||
</form>
|
||||
</div>
|
||||
</style></div>
|
||||
</ul>
|
||||
|
||||
|
||||
<!--End mc_embed_signup-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="main-content" class="span9">
|
||||
<p><a class="github" href="https://github.com/tomchristie/django-rest-framework/tree/master/rest_framework/renderers.py"><span class="label label-info">renderers.py</span></a></p>
|
||||
<h1 id="renderers">Renderers</h1>
|
||||
<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>— <a href="https://docs.djangoproject.com/en/dev/ref/template-response/#the-rendering-process">Django documentation</a></p>
|
||||
</blockquote>
|
||||
<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 flexibility 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.html">content negotiation</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_RENDERER_CLASSES</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_RENDERER_CLASSES': (
|
||||
'rest_framework.renderers.YAMLRenderer',
|
||||
'rest_framework.renderers.BrowsableAPIRenderer',
|
||||
)
|
||||
}
|
||||
</code></pre>
|
||||
<p>You can also set the renderers used for an individual view, or viewset,
|
||||
using the <code>APIView</code> class based views.</p>
|
||||
<pre class="prettyprint lang-py"><code>from django.contrib.auth.models import User
|
||||
from rest_framework.renderers import JSONRenderer, YAMLRenderer
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.views import APIView
|
||||
|
||||
class UserCountView(APIView):
|
||||
"""
|
||||
A view that returns the count of active users, in JSON or YAML.
|
||||
"""
|
||||
renderer_classes = (JSONRenderer, YAMLRenderer)
|
||||
|
||||
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 browsable 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>
|
||||
<hr />
|
||||
<h1 id="api-reference">API Reference</h1>
|
||||
<h2 id="jsonrenderer">JSONRenderer</h2>
|
||||
<p>Renders the request data into <code>JSON</code>, using utf-8 encoding.</p>
|
||||
<p>Note that non-ascii characters will be rendered using JSON's <code>\uXXXX</code> character escape. For example:</p>
|
||||
<pre class="prettyprint lang-py"><code>{"unicode black star": "\u2605"}
|
||||
</code></pre>
|
||||
<p>The client may additionally include an <code>'indent'</code> media type parameter, in which case the returned <code>JSON</code> will be indented. For example <code>Accept: application/json; indent=4</code>.</p>
|
||||
<pre class="prettyprint lang-py"><code>{
|
||||
"unicode black star": "\u2605"
|
||||
}
|
||||
</code></pre>
|
||||
<p><strong>.media_type</strong>: <code>application/json</code></p>
|
||||
<p><strong>.format</strong>: <code>'.json'</code></p>
|
||||
<p><strong>.charset</strong>: <code>None</code></p>
|
||||
<h2 id="unicodejsonrenderer">UnicodeJSONRenderer</h2>
|
||||
<p>Renders the request data into <code>JSON</code>, using utf-8 encoding.</p>
|
||||
<p>Note that non-ascii characters will not be character escaped. For example:</p>
|
||||
<pre class="prettyprint lang-py"><code>{"unicode black star": "★"}
|
||||
</code></pre>
|
||||
<p>The client may additionally include an <code>'indent'</code> media type parameter, in which case the returned <code>JSON</code> will be indented. For example <code>Accept: application/json; indent=4</code>.</p>
|
||||
<pre class="prettyprint lang-py"><code>{
|
||||
"unicode black star": "★"
|
||||
}
|
||||
</code></pre>
|
||||
<p>Both the <code>JSONRenderer</code> and <code>UnicodeJSONRenderer</code> styles conform to <a href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>, and are syntactically valid JSON.</p>
|
||||
<p><strong>.media_type</strong>: <code>application/json</code></p>
|
||||
<p><strong>.format</strong>: <code>'.json'</code></p>
|
||||
<p><strong>.charset</strong>: <code>None</code></p>
|
||||
<h2 id="jsonprenderer">JSONPRenderer</h2>
|
||||
<p>Renders the request data into <code>JSONP</code>. The <code>JSONP</code> media type provides a mechanism of allowing cross-domain AJAX requests, by wrapping a <code>JSON</code> response in a javascript callback.</p>
|
||||
<p>The javascript callback function must be set by the client including a <code>callback</code> URL query parameter. For example <code>http://example.com/api/users?callback=jsonpCallback</code>. If the callback function is not explicitly set by the client it will default to <code>'callback'</code>.</p>
|
||||
<p><strong>Note</strong>: If you require cross-domain AJAX requests, you may want to consider using the more modern approach of <a href="http://www.w3.org/TR/cors/">CORS</a> as an alternative to <code>JSONP</code>. See the <a href="../topics/ajax-csrf-cors.html">CORS documentation</a> for more details.</p>
|
||||
<p><strong>.media_type</strong>: <code>application/javascript</code></p>
|
||||
<p><strong>.format</strong>: <code>'.jsonp'</code></p>
|
||||
<p><strong>.charset</strong>: <code>utf-8</code></p>
|
||||
<h2 id="yamlrenderer">YAMLRenderer</h2>
|
||||
<p>Renders the request data into <code>YAML</code>. </p>
|
||||
<p>Requires the <code>pyyaml</code> package to be installed.</p>
|
||||
<p><strong>.media_type</strong>: <code>application/yaml</code></p>
|
||||
<p><strong>.format</strong>: <code>'.yaml'</code></p>
|
||||
<p><strong>.charset</strong>: <code>utf-8</code></p>
|
||||
<h2 id="xmlrenderer">XMLRenderer</h2>
|
||||
<p>Renders REST framework's default style of <code>XML</code> response content.</p>
|
||||
<p>Note that the <code>XML</code> markup language is used typically used as the base language for more strictly defined domain-specific languages, such as <code>RSS</code>, <code>Atom</code>, and <code>XHTML</code>.</p>
|
||||
<p>If you are considering using <code>XML</code> for your API, you may want to consider implementing a custom renderer and parser for your specific requirements, and using an existing domain-specific media-type, or creating your own custom XML-based media-type.</p>
|
||||
<p><strong>.media_type</strong>: <code>application/xml</code></p>
|
||||
<p><strong>.format</strong>: <code>'.xml'</code></p>
|
||||
<p><strong>.charset</strong>: <code>utf-8</code></p>
|
||||
<h2 id="templatehtmlrenderer">TemplateHTMLRenderer</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 TemplateHTMLRenderer 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> argument passed to 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>An example of a view that uses <code>TemplateHTMLRenderer</code>:</p>
|
||||
<pre class="prettyprint lang-py"><code>class UserDetail(generics.RetrieveUserAPIView):
|
||||
"""
|
||||
A view that returns a templated HTML representations of a given user.
|
||||
"""
|
||||
queryset = User.objects.all()
|
||||
renderer_classes = (TemplateHTMLRenderer,)
|
||||
|
||||
def get(self, request, *args, **kwargs)
|
||||
self.object = self.get_object()
|
||||
return Response({'user': self.object}, template_name='user_detail.html')
|
||||
</code></pre>
|
||||
<p>You can use <code>TemplateHTMLRenderer</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>TemplateHTMLRenderer</code> along with other renderer classes, you should consider listing <code>TemplateHTMLRenderer</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 <code>ACCEPT:</code> headers.</p>
|
||||
<p><strong>.media_type</strong>: <code>text/html</code></p>
|
||||
<p><strong>.format</strong>: <code>'.html'</code></p>
|
||||
<p><strong>.charset</strong>: <code>utf-8</code></p>
|
||||
<p>See also: <code>StaticHTMLRenderer</code></p>
|
||||
<h2 id="statichtmlrenderer">StaticHTMLRenderer</h2>
|
||||
<p>A simple renderer that simply returns pre-rendered HTML. Unlike other renderers, the data passed to the response object should be a string representing the content to be returned.</p>
|
||||
<p>An example of a view that uses <code>TemplateHTMLRenderer</code>:</p>
|
||||
<pre class="prettyprint lang-py"><code>@api_view(('GET',))
|
||||
@renderer_classes((StaticHTMLRenderer,))
|
||||
def simple_html_view(request):
|
||||
data = '<html><body><h1>Hello, world</h1></body></html>'
|
||||
return Response(data)
|
||||
</code></pre>
|
||||
<p>You can use <code>TemplateHTMLRenderer</code> either to return regular HTML pages using REST framework, or to return both HTML and API responses from a single endpoint.</p>
|
||||
<p><strong>.media_type</strong>: <code>text/html</code></p>
|
||||
<p><strong>.format</strong>: <code>'.html'</code></p>
|
||||
<p><strong>.charset</strong>: <code>utf-8</code></p>
|
||||
<p>See also: <code>TemplateHTMLRenderer</code></p>
|
||||
<h2 id="htmlformrenderer">HTMLFormRenderer</h2>
|
||||
<p>Renders data returned by a serializer into an HTML form. The output of this renderer does not include the enclosing <code><form></code> tags or an submit actions, as you'll probably need those to include the desired method and URL. Also note that the <code>HTMLFormRenderer</code> does not yet support including field error messages.</p>
|
||||
<p>Note that the template used by the <code>HTMLFormRenderer</code> class, and the context submitted to it <strong>may be subject to change</strong>. If you need to use this renderer class it is advised that you either make a local copy of the class and templates, or follow the release note on REST framework upgrades closely.</p>
|
||||
<p><strong>.media_type</strong>: <code>text/html</code></p>
|
||||
<p><strong>.format</strong>: <code>'.form'</code></p>
|
||||
<p><strong>.charset</strong>: <code>utf-8</code></p>
|
||||
<p><strong>.template</strong>: <code>'rest_framework/form.html'</code></p>
|
||||
<h2 id="browsableapirenderer">BrowsableAPIRenderer</h2>
|
||||
<p>Renders data into HTML for the Browsable 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>
|
||||
<p><strong>.media_type</strong>: <code>text/html</code></p>
|
||||
<p><strong>.format</strong>: <code>'.api'</code></p>
|
||||
<p><strong>.charset</strong>: <code>utf-8</code></p>
|
||||
<p><strong>.template</strong>: <code>'rest_framework/api.html'</code></p>
|
||||
<h4 id="customizing-browsableapirenderer">Customizing BrowsableAPIRenderer</h4>
|
||||
<p>By default the response content will be rendered with the highest priority renderer apart from <code>BrowseableAPIRenderer</code>. If you need to customize this behavior, for example to use HTML as the default return format, but use JSON in the browsable API, you can do so by overriding the <code>get_default_renderer()</code> method. For example:</p>
|
||||
<pre class="prettyprint lang-py"><code>class CustomBrowsableAPIRenderer(BrowsableAPIRenderer):
|
||||
def get_default_renderer(self, view):
|
||||
return JSONRenderer()
|
||||
</code></pre>
|
||||
<h2 id="multipartrenderer">MultiPartRenderer</h2>
|
||||
<p>This renderer is used for rendering HTML multipart form data. <strong>It is not suitable as a response renderer</strong>, but is instead used for creating test requests, using REST framework's <a href="testing.html">test client and test request factory</a>.</p>
|
||||
<p><strong>.media_type</strong>: <code>multipart/form-data; boundary=BoUnDaRyStRiNg</code></p>
|
||||
<p><strong>.format</strong>: <code>'.multipart'</code></p>
|
||||
<p><strong>.charset</strong>: <code>utf-8</code></p>
|
||||
<hr />
|
||||
<h1 id="custom-renderers">Custom renderers</h1>
|
||||
<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=None, renderer_context=None)</code> method.</p>
|
||||
<p>The method should return a bytestring, which will be used as the body of the HTTP response.</p>
|
||||
<p>The arguments passed to the <code>.render()</code> method are:</p>
|
||||
<h3 id="data"><code>data</code></h3>
|
||||
<p>The request data, as set by the <code>Response()</code> instantiation.</p>
|
||||
<h3 id="media_typenone"><code>media_type=None</code></h3>
|
||||
<p>Optional. If provided, this is the accepted media type, as determined by the content negotiation stage.</p>
|
||||
<p>Depending on the client's <code>Accept:</code> header, this may be more specific than the renderer's <code>media_type</code> attribute, and may include media type parameters. For example <code>"application/json; nested=true"</code>.</p>
|
||||
<h3 id="renderer_contextnone"><code>renderer_context=None</code></h3>
|
||||
<p>Optional. If provided, this is a dictionary of contextual information provided by the view.</p>
|
||||
<p>By default this will include the following keys: <code>view</code>, <code>request</code>, <code>response</code>, <code>args</code>, <code>kwargs</code>.</p>
|
||||
<h2 id="example">Example</h2>
|
||||
<p>The following is an example plaintext renderer that will return a response with the <code>data</code> parameter as the content of the response.</p>
|
||||
<pre class="prettyprint lang-py"><code>from django.utils.encoding import smart_unicode
|
||||
from rest_framework import renderers
|
||||
|
||||
|
||||
class PlainTextRenderer(renderers.BaseRenderer):
|
||||
media_type = 'text/plain'
|
||||
format = 'txt'
|
||||
|
||||
def render(self, data, media_type=None, renderer_context=None):
|
||||
return data.encode(self.charset)
|
||||
</code></pre>
|
||||
<h2 id="setting-the-character-set">Setting the character set</h2>
|
||||
<p>By default renderer classes are assumed to be using the <code>UTF-8</code> encoding. To use a different encoding, set the <code>charset</code> attribute on the renderer.</p>
|
||||
<pre class="prettyprint lang-py"><code>class PlainTextRenderer(renderers.BaseRenderer):
|
||||
media_type = 'text/plain'
|
||||
format = 'txt'
|
||||
charset = 'iso-8859-1'
|
||||
|
||||
def render(self, data, media_type=None, renderer_context=None):
|
||||
return data.encode(self.charset)
|
||||
</code></pre>
|
||||
<p>Note that if a renderer class returns a unicode string, then the response content will be coerced into a bytestring by the <code>Response</code> class, with the <code>charset</code> attribute set on the renderer used to determine the encoding.</p>
|
||||
<p>If the renderer returns a bytestring representing raw binary content, you should set a charset value of <code>None</code>, which will ensure the <code>Content-Type</code> header of the response will not have a <code>charset</code> value set.</p>
|
||||
<p>In some cases you may also want to set the <code>render_style</code> attribute to <code>'binary'</code>. Doing so will also ensure that the browsable API will not attempt to display the binary content as a string.</p>
|
||||
<pre class="prettyprint lang-py"><code>class JPEGRenderer(renderers.BaseRenderer):
|
||||
media_type = 'image/jpeg'
|
||||
format = 'jpg'
|
||||
charset = None
|
||||
render_style = 'binary'
|
||||
|
||||
def render(self, data, media_type=None, renderer_context=None):
|
||||
return data
|
||||
</code></pre>
|
||||
<hr />
|
||||
<h1 id="advanced-renderer-usage">Advanced renderer usage</h1>
|
||||
<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>
|
||||
<h2 id="varying-behaviour-by-media-type">Varying behaviour by media type</h2>
|
||||
<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)
|
||||
|
||||
if request.accepted_renderer.format == 'html':
|
||||
# TemplateHTMLRenderer takes a context dict,
|
||||
# and additionally requires a 'template_name'.
|
||||
# It does not require serialization.
|
||||
data = {'users': queryset}
|
||||
return Response(data, template_name='list_users.html')
|
||||
|
||||
# JSONRenderer requires serialized data as normal.
|
||||
serializer = UserSerializer(instance=queryset)
|
||||
data = serializer.data
|
||||
return Response(data)
|
||||
</code></pre>
|
||||
<h2 id="underspecifying-the-media-type">Underspecifying the media type</h2>
|
||||
<p>In some cases you might want a renderer to serve a range of media types.
|
||||
In this case you can underspecify the media types it should respond to, by using a <code>media_type</code> value such as <code>image/*</code>, or <code>*/*</code>.</p>
|
||||
<p>If you underspecify the renderer's media type, you should make sure to specify the media type explicitly when you return the response, using the <code>content_type</code> attribute. For example:</p>
|
||||
<pre class="prettyprint lang-py"><code>return Response(data, content_type='image/png')
|
||||
</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 need 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>
|
||||
<h2 id="html-error-views">HTML error views</h2>
|
||||
<p>Typically a renderer will behave the same regardless of if it's dealing with a regular response, or with a response caused by an exception being raised, such as an <code>Http404</code> or <code>PermissionDenied</code> exception, or a subclass of <code>APIException</code>.</p>
|
||||
<p>If you're using either the <code>TemplateHTMLRenderer</code> or the <code>StaticHTMLRenderer</code> and an exception is raised, the behavior is slightly different, and mirrors <a href="https://docs.djangoproject.com/en/dev/topics/http/views/#customizing-error-views">Django's default handling of error views</a>.</p>
|
||||
<p>Exceptions raised and handled by an HTML renderer will attempt to render using one of the following methods, by order of precedence.</p>
|
||||
<ul>
|
||||
<li>Load and render a template named <code>{status_code}.html</code>.</li>
|
||||
<li>Load and render a template named <code>api_exception.html</code>.</li>
|
||||
<li>Render the HTTP status code and text, for example "404 Not Found".</li>
|
||||
</ul>
|
||||
<p>Templates will render with a <code>RequestContext</code> which includes the <code>status_code</code> and <code>details</code> keys.</p>
|
||||
<p><strong>Note</strong>: If <code>DEBUG=True</code>, Django's standard traceback error page will be displayed instead of rendering the HTTP status code and text.</p>
|
||||
<hr />
|
||||
<h1 id="third-party-packages">Third party packages</h1>
|
||||
<p>The following third party packages are also available.</p>
|
||||
<h2 id="messagepack">MessagePack</h2>
|
||||
<p><a href="http://msgpack.org/">MessagePack</a> is a fast, efficient binary serialization format. <a href="https://github.com/juanriaza">Juan Riaza</a> maintains the <a href="https://github.com/juanriaza/django-rest-framework-msgpack">djangorestframework-msgpack</a> package which provides MessagePack renderer and parser support for REST framework.</p>
|
||||
<h2 id="csv">CSV</h2>
|
||||
<p>Comma-separated values are a plain-text tabular data format, that can be easily imported into spreadsheet applications. <a href="https://github.com/mjumbewu">Mjumbe Poe</a> maintains the <a href="https://github.com/mjumbewu/django-rest-framework-csv">djangorestframework-csv</a> package which provides CSV renderer support for REST framework.</p>
|
||||
<h2 id="ultrajson">UltraJSON</h2>
|
||||
<p><a href="https://github.com/esnme/ultrajson">UltraJSON</a> is an optimized C JSON encoder which can give significantly faster JSON rendering. <a href="https://github.com/hzy">Jacob Haslehurst</a> maintains the <a href="https://github.com/gizmag/drf-ujson-renderer">drf-ujson-renderer</a> package which implements JSON rendering using the UJSON package.</p>
|
||||
</div><!--/span-->
|
||||
</div><!--/row-->
|
||||
</div><!--/.fluid-container-->
|
||||
</div><!--/.body content-->
|
||||
|
||||
<div id="push"></div>
|
||||
</div><!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a></p>
|
||||
</footer>
|
||||
|
||||
<!-- Le javascript
|
||||
================================================== -->
|
||||
<!-- Placed at the end of the document so the pages load faster -->
|
||||
<script src="http://django-rest-framework.org/js/jquery-1.8.1-min.js"></script>
|
||||
<script src="http://django-rest-framework.org/js/prettify-1.0.js"></script>
|
||||
<script src="http://django-rest-framework.org/js/bootstrap-2.1.1-min.js"></script>
|
||||
<script>
|
||||
//$('.side-nav').scrollspy()
|
||||
var shiftWindow = function() { scrollBy(0, -50) };
|
||||
if (location.hash) shiftWindow();
|
||||
window.addEventListener("hashchange", shiftWindow);
|
||||
|
||||
$('.dropdown-menu').on('click touchstart', function(event) {
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
// Dynamically force sidenav to no higher than browser window
|
||||
$('.side-nav').css('max-height', window.innerHeight - 130);
|
||||
|
||||
$(function(){
|
||||
$(window).resize(function(){
|
||||
$('.side-nav').css('max-height', window.innerHeight - 130);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body></html>
|
||||
321
api-guide/requests.html
Normal file
321
api-guide/requests.html
Normal file
|
|
@ -0,0 +1,321 @@
|
|||
<!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 - Requests</title>
|
||||
<link href="http://django-rest-framework.org/img/favicon.ico" rel="icon" type="image/x-icon">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Django, API, REST, Requests, Request parsing, Authentication, Browser enhancements, Standard HttpRequest attributes">
|
||||
<meta name="author" content="Tom Christie">
|
||||
|
||||
<!-- Le styles -->
|
||||
<link href="http://django-rest-framework.org/css/prettify.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/bootstrap.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/bootstrap-responsive.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/default.css" rel="stylesheet">
|
||||
|
||||
<!-- 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]-->
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-18852272-2']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="prettyPrint()" class="requests-page">
|
||||
|
||||
<div class="wrapper">
|
||||
|
||||
<div class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container-fluid">
|
||||
<a class="repo-link btn btn-primary btn-small" href="https://github.com/tomchristie/django-rest-framework/tree/master">GitHub</a>
|
||||
<a class="repo-link btn btn-inverse btn-small " href="../api-guide/responses.html">Next <i class="icon-arrow-right icon-white"></i></a>
|
||||
<a class="repo-link btn btn-inverse btn-small " href="../tutorial/6-viewsets-and-routers.html"><i class="icon-arrow-left icon-white"></i> Previous</a>
|
||||
<a class="repo-link btn btn-inverse btn-small" href="#searchModal" data-toggle="modal"><i class="icon-search icon-white"></i> Search</a>
|
||||
<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>
|
||||
<a class="brand" href="http://django-rest-framework.org">Django REST framework</a>
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav">
|
||||
<li><a href="http://django-rest-framework.org">Home</a></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Tutorial <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/tutorial/quickstart.html">Quickstart</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/1-serialization.html">1 - Serialization</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/2-requests-and-responses.html">2 - Requests and responses</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/3-class-based-views.html">3 - Class based views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/4-authentication-and-permissions.html">4 - Authentication and permissions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/5-relationships-and-hyperlinked-apis.html">5 - Relationships and hyperlinked APIs</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/6-viewsets-and-routers.html">6 - Viewsets and routers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">API Guide <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/api-guide/requests.html">Requests</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/responses.html">Responses</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/views.html">Views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/generic-views.html">Generic views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/viewsets.html">Viewsets</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/routers.html">Routers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/parsers.html">Parsers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/renderers.html">Renderers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/serializers.html">Serializers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/fields.html">Serializer fields</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/relations.html">Serializer relations</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/authentication.html">Authentication</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/permissions.html">Permissions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/throttling.html">Throttling</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/filtering.html">Filtering</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/pagination.html">Pagination</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/content-negotiation.html">Content negotiation</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/format-suffixes.html">Format suffixes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/reverse.html">Returning URLs</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/exceptions.html">Exceptions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/status-codes.html">Status codes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/testing.html">Testing</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/settings.html">Settings</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Topics <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/topics/documenting-your-api.html">Documenting your API</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/ajax-csrf-cors.html">AJAX, CSRF & CORS</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/browser-enhancements.html">Browser enhancements</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/browsable-api.html">The Browsable API</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/rest-hypermedia-hateoas.html">REST, Hypermedia & HATEOAS</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/rest-framework-2-announcement.html">2.0 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/2.2-announcement.html">2.2 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/2.3-announcement.html">2.3 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/release-notes.html">Release Notes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/credits.html">Credits</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="nav pull-right">
|
||||
<!-- TODO
|
||||
<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>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="body-content">
|
||||
<div class="container-fluid">
|
||||
|
||||
<!-- Search Modal -->
|
||||
<div id="searchModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3 id="myModalLabel">Documentation search</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<!-- Custom google search -->
|
||||
<script>
|
||||
(function() {
|
||||
var cx = '015016005043623903336:rxraeohqk6w';
|
||||
var gcse = document.createElement('script');
|
||||
gcse.type = 'text/javascript';
|
||||
gcse.async = true;
|
||||
gcse.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') +
|
||||
'//www.google.com/cse/cse.js?cx=' + cx;
|
||||
var s = document.getElementsByTagName('script')[0];
|
||||
s.parentNode.insertBefore(gcse, s);
|
||||
})();
|
||||
</script>
|
||||
<gcse:search></gcse:search>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row-fluid">
|
||||
|
||||
<div class="span3">
|
||||
<!-- TODO
|
||||
<p style="margin-top: -12px">
|
||||
<a class="btn btn-mini btn-primary" style="width: 60px">« previous</a>
|
||||
<a class="btn btn-mini btn-primary" style="float: right; margin-right: 8px; width: 60px;">next »</a>
|
||||
</p>
|
||||
-->
|
||||
<div id="table-of-contents">
|
||||
<ul class="nav nav-list side-nav well sidebar-nav-fixed">
|
||||
<li class="main"><a href="#requests">Requests</a></li>
|
||||
<li class="main"><a href="#request-parsing">Request parsing</a></li>
|
||||
<li><a href="#data">.DATA</a></li>
|
||||
<li><a href="#files">.FILES</a></li>
|
||||
<li><a href="#query_params">.QUERY_PARAMS</a></li>
|
||||
<li><a href="#parsers">.parsers</a></li>
|
||||
<li class="main"><a href="#authentication">Authentication</a></li>
|
||||
<li><a href="#user">.user</a></li>
|
||||
<li><a href="#auth">.auth</a></li>
|
||||
<li><a href="#authenticators">.authenticators</a></li>
|
||||
<li class="main"><a href="#browser-enhancements">Browser enhancements</a></li>
|
||||
<li><a href="#method">.method</a></li>
|
||||
<li><a href="#content_type">.content_type</a></li>
|
||||
<li><a href="#stream">.stream</a></li>
|
||||
<li class="main"><a href="#standard-httprequest-attributes">Standard HttpRequest attributes</a></li>
|
||||
|
||||
<div>
|
||||
<hr>
|
||||
|
||||
<p><strong>The team behind REST framework are launching a new API service.</strong></p>
|
||||
|
||||
<p>If you want to be first in line when we start issuing invitations, please sign up here:</p>
|
||||
|
||||
<!-- Begin MailChimp Signup Form -->
|
||||
<link href="//cdn-images.mailchimp.com/embedcode/slim-081711.css" rel="stylesheet" type="text/css">
|
||||
<style type="text/css">
|
||||
#mc_embed_signup{background:#fff; clear:left; font:14px Helvetica,Arial,sans-serif; }
|
||||
/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
|
||||
We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
|
||||
</style>
|
||||
<div id="mc_embed_signup" style="background: rgb(245, 245, 245)">
|
||||
<form action="http://dabapps.us1.list-manage1.com/subscribe/post?u=cf73a9994eb5b8d8d461b5dfb&id=cb6af8e8bd" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>
|
||||
<!-- <label for="mce-EMAIL">Keep me posted!</label>
|
||||
--> <input style="width: 90%" type="email" value="" name="EMAIL" class="email" id="mce-EMAIL" placeholder="email address" required>
|
||||
<div class="clear"><input class="btn btn-success" type="submit" value="Yes, keep me posted!" name="subscribe" id="mc-embedded-subscribe" class="button"></div>
|
||||
</form>
|
||||
</div>
|
||||
</style></div>
|
||||
</ul>
|
||||
|
||||
|
||||
<!--End mc_embed_signup-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="main-content" class="span9">
|
||||
<p><a class="github" href="https://github.com/tomchristie/django-rest-framework/tree/master/rest_framework/request.py"><span class="label label-info">request.py</span></a></p>
|
||||
<h1 id="requests">Requests</h1>
|
||||
<blockquote>
|
||||
<p>If you're doing REST-based web service stuff ... you should ignore request.POST.</p>
|
||||
<p>— Malcom Tredinnick, <a href="https://groups.google.com/d/topic/django-developers/dxI4qVzrBY4/discussion">Django developers group</a></p>
|
||||
</blockquote>
|
||||
<p>REST framework's <code>Request</code> class extends the standard <code>HttpRequest</code>, adding support for REST framework's flexible request parsing and request authentication.</p>
|
||||
<hr />
|
||||
<h1 id="request-parsing">Request parsing</h1>
|
||||
<p>REST framework's Request objects provide flexible request parsing that allows you to treat requests with JSON data or other media types in the same way that you would normally deal with form data.</p>
|
||||
<h2 id="data">.DATA</h2>
|
||||
<p><code>request.DATA</code> returns the parsed content of the request body. This is similar to the standard <code>request.POST</code> attribute except that:</p>
|
||||
<ul>
|
||||
<li>It supports parsing the content of HTTP methods other than <code>POST</code>, meaning that you can access the content of <code>PUT</code> and <code>PATCH</code> requests.</li>
|
||||
<li>It supports REST framework's flexible request parsing, rather than just supporting form data. For example you can handle incoming JSON data in the same way that you handle incoming form data.</li>
|
||||
</ul>
|
||||
<p>For more details see the <a href="parsers.html">parsers documentation</a>.</p>
|
||||
<h2 id="files">.FILES</h2>
|
||||
<p><code>request.FILES</code> returns any uploaded files that may be present in the content of the request body. This is the same as the standard <code>HttpRequest</code> behavior, except that the same flexible request parsing is used for <code>request.DATA</code>.</p>
|
||||
<p>For more details see the <a href="parsers.html">parsers documentation</a>.</p>
|
||||
<h2 id="query_params">.QUERY_PARAMS</h2>
|
||||
<p><code>request.QUERY_PARAMS</code> is a more correctly named synonym for <code>request.GET</code>.</p>
|
||||
<p>For clarity inside your code, we recommend using <code>request.QUERY_PARAMS</code> instead of the usual <code>request.GET</code>, as <em>any</em> HTTP method type may include query parameters.</p>
|
||||
<h2 id="parsers">.parsers</h2>
|
||||
<p>The <code>APIView</code> class or <code>@api_view</code> decorator will ensure that this property is automatically set to a list of <code>Parser</code> instances, based on the <code>parser_classes</code> set on the view or based on the <code>DEFAULT_PARSER_CLASSES</code> setting.</p>
|
||||
<p>You won't typically need to access this property.</p>
|
||||
<hr />
|
||||
<p><strong>Note:</strong> If a client sends malformed content, then accessing <code>request.DATA</code> or <code>request.FILES</code> may raise a <code>ParseError</code>. By default REST framework's <code>APIView</code> class or <code>@api_view</code> decorator will catch the error and return a <code>400 Bad Request</code> response.</p>
|
||||
<p>If a client sends a request with a content-type that cannot be parsed then a <code>UnsupportedMediaType</code> exception will be raised, which by default will be caught and return a <code>415 Unsupported Media Type</code> response.</p>
|
||||
<hr />
|
||||
<h1 id="authentication">Authentication</h1>
|
||||
<p>REST framework provides flexible, per-request authentication, that gives you the ability to:</p>
|
||||
<ul>
|
||||
<li>Use different authentication policies for different parts of your API.</li>
|
||||
<li>Support the use of multiple authentication policies.</li>
|
||||
<li>Provide both user and token information associated with the incoming request.</li>
|
||||
</ul>
|
||||
<h2 id="user">.user</h2>
|
||||
<p><code>request.user</code> typically returns an instance of <code>django.contrib.auth.models.User</code>, although the behavior depends on the authentication policy being used.</p>
|
||||
<p>If the request is unauthenticated the default value of <code>request.user</code> is an instance of <code>django.contrib.auth.models.AnonymousUser</code>.</p>
|
||||
<p>For more details see the <a href="authentication.html">authentication documentation</a>.</p>
|
||||
<h2 id="auth">.auth</h2>
|
||||
<p><code>request.auth</code> returns any additional authentication context. The exact behavior of <code>request.auth</code> depends on the authentication policy being used, but it may typically be an instance of the token that the request was authenticated against.</p>
|
||||
<p>If the request is unauthenticated, or if no additional context is present, the default value of <code>request.auth</code> is <code>None</code>.</p>
|
||||
<p>For more details see the <a href="authentication.html">authentication documentation</a>.</p>
|
||||
<h2 id="authenticators">.authenticators</h2>
|
||||
<p>The <code>APIView</code> class or <code>@api_view</code> decorator will ensure that this property is automatically set to a list of <code>Authentication</code> instances, based on the <code>authentication_classes</code> set on the view or based on the <code>DEFAULT_AUTHENTICATORS</code> setting.</p>
|
||||
<p>You won't typically need to access this property.</p>
|
||||
<hr />
|
||||
<h1 id="browser-enhancements">Browser enhancements</h1>
|
||||
<p>REST framework supports a few browser enhancements such as browser-based <code>PUT</code>, <code>PATCH</code> and <code>DELETE</code> forms.</p>
|
||||
<h2 id="method">.method</h2>
|
||||
<p><code>request.method</code> returns the <strong>uppercased</strong> string representation of the request's HTTP method.</p>
|
||||
<p>Browser-based <code>PUT</code>, <code>PATCH</code> and <code>DELETE</code> forms are transparently supported.</p>
|
||||
<p>For more information see the <a href="../topics/browser-enhancements.html">browser enhancements documentation</a>. </p>
|
||||
<h2 id="content_type">.content_type</h2>
|
||||
<p><code>request.content_type</code>, returns a string object representing the media type of the HTTP request's body, or an empty string if no media type was provided.</p>
|
||||
<p>You won't typically need to directly access the request's content type, as you'll normally rely on REST framework's default request parsing behavior.</p>
|
||||
<p>If you do need to access the content type of the request you should use the <code>.content_type</code> property in preference to using <code>request.META.get('HTTP_CONTENT_TYPE')</code>, as it provides transparent support for browser-based non-form content.</p>
|
||||
<p>For more information see the <a href="../topics/browser-enhancements.html">browser enhancements documentation</a>. </p>
|
||||
<h2 id="stream">.stream</h2>
|
||||
<p><code>request.stream</code> returns a stream representing the content of the request body.</p>
|
||||
<p>You won't typically need to directly access the request's content, as you'll normally rely on REST framework's default request parsing behavior.</p>
|
||||
<p>If you do need to access the raw content directly, you should use the <code>.stream</code> property in preference to using <code>request.content</code>, as it provides transparent support for browser-based non-form content.</p>
|
||||
<p>For more information see the <a href="../topics/browser-enhancements.html">browser enhancements documentation</a>. </p>
|
||||
<hr />
|
||||
<h1 id="standard-httprequest-attributes">Standard HttpRequest attributes</h1>
|
||||
<p>As REST framework's <code>Request</code> extends Django's <code>HttpRequest</code>, all the other standard attributes and methods are also available. For example the <code>request.META</code> and <code>request.session</code> dictionaries are available as normal.</p>
|
||||
<p>Note that due to implementation reasons the <code>Request</code> class does not inherit from <code>HttpRequest</code> class, but instead extends the class using composition.</p>
|
||||
</div><!--/span-->
|
||||
</div><!--/row-->
|
||||
</div><!--/.fluid-container-->
|
||||
</div><!--/.body content-->
|
||||
|
||||
<div id="push"></div>
|
||||
</div><!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a></p>
|
||||
</footer>
|
||||
|
||||
<!-- Le javascript
|
||||
================================================== -->
|
||||
<!-- Placed at the end of the document so the pages load faster -->
|
||||
<script src="http://django-rest-framework.org/js/jquery-1.8.1-min.js"></script>
|
||||
<script src="http://django-rest-framework.org/js/prettify-1.0.js"></script>
|
||||
<script src="http://django-rest-framework.org/js/bootstrap-2.1.1-min.js"></script>
|
||||
<script>
|
||||
//$('.side-nav').scrollspy()
|
||||
var shiftWindow = function() { scrollBy(0, -50) };
|
||||
if (location.hash) shiftWindow();
|
||||
window.addEventListener("hashchange", shiftWindow);
|
||||
|
||||
$('.dropdown-menu').on('click touchstart', function(event) {
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
// Dynamically force sidenav to no higher than browser window
|
||||
$('.side-nav').css('max-height', window.innerHeight - 130);
|
||||
|
||||
$(function(){
|
||||
$(window).resize(function(){
|
||||
$('.side-nav').css('max-height', window.innerHeight - 130);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body></html>
|
||||
304
api-guide/responses.html
Normal file
304
api-guide/responses.html
Normal file
|
|
@ -0,0 +1,304 @@
|
|||
<!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 - Responses</title>
|
||||
<link href="http://django-rest-framework.org/img/favicon.ico" rel="icon" type="image/x-icon">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Django, API, REST, Responses, Creating responses, Attributes, Standard HttpResponse attributes">
|
||||
<meta name="author" content="Tom Christie">
|
||||
|
||||
<!-- Le styles -->
|
||||
<link href="http://django-rest-framework.org/css/prettify.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/bootstrap.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/bootstrap-responsive.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/default.css" rel="stylesheet">
|
||||
|
||||
<!-- 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]-->
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-18852272-2']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="prettyPrint()" class="responses-page">
|
||||
|
||||
<div class="wrapper">
|
||||
|
||||
<div class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container-fluid">
|
||||
<a class="repo-link btn btn-primary btn-small" href="https://github.com/tomchristie/django-rest-framework/tree/master">GitHub</a>
|
||||
<a class="repo-link btn btn-inverse btn-small " href="../api-guide/views.html">Next <i class="icon-arrow-right icon-white"></i></a>
|
||||
<a class="repo-link btn btn-inverse btn-small " href="../api-guide/requests.html"><i class="icon-arrow-left icon-white"></i> Previous</a>
|
||||
<a class="repo-link btn btn-inverse btn-small" href="#searchModal" data-toggle="modal"><i class="icon-search icon-white"></i> Search</a>
|
||||
<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>
|
||||
<a class="brand" href="http://django-rest-framework.org">Django REST framework</a>
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav">
|
||||
<li><a href="http://django-rest-framework.org">Home</a></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Tutorial <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/tutorial/quickstart.html">Quickstart</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/1-serialization.html">1 - Serialization</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/2-requests-and-responses.html">2 - Requests and responses</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/3-class-based-views.html">3 - Class based views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/4-authentication-and-permissions.html">4 - Authentication and permissions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/5-relationships-and-hyperlinked-apis.html">5 - Relationships and hyperlinked APIs</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/6-viewsets-and-routers.html">6 - Viewsets and routers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">API Guide <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/api-guide/requests.html">Requests</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/responses.html">Responses</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/views.html">Views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/generic-views.html">Generic views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/viewsets.html">Viewsets</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/routers.html">Routers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/parsers.html">Parsers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/renderers.html">Renderers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/serializers.html">Serializers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/fields.html">Serializer fields</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/relations.html">Serializer relations</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/authentication.html">Authentication</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/permissions.html">Permissions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/throttling.html">Throttling</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/filtering.html">Filtering</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/pagination.html">Pagination</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/content-negotiation.html">Content negotiation</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/format-suffixes.html">Format suffixes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/reverse.html">Returning URLs</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/exceptions.html">Exceptions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/status-codes.html">Status codes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/testing.html">Testing</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/settings.html">Settings</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Topics <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/topics/documenting-your-api.html">Documenting your API</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/ajax-csrf-cors.html">AJAX, CSRF & CORS</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/browser-enhancements.html">Browser enhancements</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/browsable-api.html">The Browsable API</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/rest-hypermedia-hateoas.html">REST, Hypermedia & HATEOAS</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/rest-framework-2-announcement.html">2.0 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/2.2-announcement.html">2.2 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/2.3-announcement.html">2.3 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/release-notes.html">Release Notes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/credits.html">Credits</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="nav pull-right">
|
||||
<!-- TODO
|
||||
<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>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="body-content">
|
||||
<div class="container-fluid">
|
||||
|
||||
<!-- Search Modal -->
|
||||
<div id="searchModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3 id="myModalLabel">Documentation search</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<!-- Custom google search -->
|
||||
<script>
|
||||
(function() {
|
||||
var cx = '015016005043623903336:rxraeohqk6w';
|
||||
var gcse = document.createElement('script');
|
||||
gcse.type = 'text/javascript';
|
||||
gcse.async = true;
|
||||
gcse.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') +
|
||||
'//www.google.com/cse/cse.js?cx=' + cx;
|
||||
var s = document.getElementsByTagName('script')[0];
|
||||
s.parentNode.insertBefore(gcse, s);
|
||||
})();
|
||||
</script>
|
||||
<gcse:search></gcse:search>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row-fluid">
|
||||
|
||||
<div class="span3">
|
||||
<!-- TODO
|
||||
<p style="margin-top: -12px">
|
||||
<a class="btn btn-mini btn-primary" style="width: 60px">« previous</a>
|
||||
<a class="btn btn-mini btn-primary" style="float: right; margin-right: 8px; width: 60px;">next »</a>
|
||||
</p>
|
||||
-->
|
||||
<div id="table-of-contents">
|
||||
<ul class="nav nav-list side-nav well sidebar-nav-fixed">
|
||||
<li class="main"><a href="#responses">Responses</a></li>
|
||||
<li class="main"><a href="#creating-responses">Creating responses</a></li>
|
||||
<li><a href="#response()">Response()</a></li>
|
||||
<li class="main"><a href="#attributes">Attributes</a></li>
|
||||
<li><a href="#data">.data</a></li>
|
||||
<li><a href="#status_code">.status_code</a></li>
|
||||
<li><a href="#content">.content</a></li>
|
||||
<li><a href="#template_name">.template_name</a></li>
|
||||
<li><a href="#accepted_renderer">.accepted_renderer</a></li>
|
||||
<li><a href="#accepted_media_type">.accepted_media_type</a></li>
|
||||
<li><a href="#renderer_context">.renderer_context</a></li>
|
||||
<li class="main"><a href="#standard-httpresponse-attributes">Standard HttpResponse attributes</a></li>
|
||||
<li><a href="#render()">.render()</a></li>
|
||||
|
||||
<div>
|
||||
<hr>
|
||||
|
||||
<p><strong>The team behind REST framework are launching a new API service.</strong></p>
|
||||
|
||||
<p>If you want to be first in line when we start issuing invitations, please sign up here:</p>
|
||||
|
||||
<!-- Begin MailChimp Signup Form -->
|
||||
<link href="//cdn-images.mailchimp.com/embedcode/slim-081711.css" rel="stylesheet" type="text/css">
|
||||
<style type="text/css">
|
||||
#mc_embed_signup{background:#fff; clear:left; font:14px Helvetica,Arial,sans-serif; }
|
||||
/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
|
||||
We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
|
||||
</style>
|
||||
<div id="mc_embed_signup" style="background: rgb(245, 245, 245)">
|
||||
<form action="http://dabapps.us1.list-manage1.com/subscribe/post?u=cf73a9994eb5b8d8d461b5dfb&id=cb6af8e8bd" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>
|
||||
<!-- <label for="mce-EMAIL">Keep me posted!</label>
|
||||
--> <input style="width: 90%" type="email" value="" name="EMAIL" class="email" id="mce-EMAIL" placeholder="email address" required>
|
||||
<div class="clear"><input class="btn btn-success" type="submit" value="Yes, keep me posted!" name="subscribe" id="mc-embedded-subscribe" class="button"></div>
|
||||
</form>
|
||||
</div>
|
||||
</style></div>
|
||||
</ul>
|
||||
|
||||
|
||||
<!--End mc_embed_signup-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="main-content" class="span9">
|
||||
<p><a class="github" href="https://github.com/tomchristie/django-rest-framework/tree/master/rest_framework/response.py"><span class="label label-info">response.py</span></a></p>
|
||||
<h1 id="responses">Responses</h1>
|
||||
<blockquote>
|
||||
<p>Unlike basic HttpResponse objects, TemplateResponse objects retain the details of the context that was provided by the view to compute the response. The final output of the response is not computed until it is needed, later in the response process.</p>
|
||||
<p>— <a href="https://docs.djangoproject.com/en/dev/ref/template-response/">Django documentation</a></p>
|
||||
</blockquote>
|
||||
<p>REST framework supports HTTP content negotiation by providing a <code>Response</code> class which allows you to return content that can be rendered into multiple content types, depending on the client request.</p>
|
||||
<p>The <code>Response</code> class subclasses Django's <code>SimpleTemplateResponse</code>. <code>Response</code> objects are initialised with data, which should consist of native Python primitives. REST framework then uses standard HTTP content negotiation to determine how it should render the final response content.</p>
|
||||
<p>There's no requirement for you to use the <code>Response</code> class, you can also return regular <code>HttpResponse</code> or <code>StreamingHttpResponse</code> objects from your views if required. Using the <code>Response</code> class simply provides a nicer interface for returning content-negotiated Web API responses, that can be rendered to multiple formats.</p>
|
||||
<p>Unless you want to heavily customize REST framework for some reason, you should always use an <code>APIView</code> class or <code>@api_view</code> function for views that return <code>Response</code> objects. Doing so ensures that the view can perform content negotiation and select the appropriate renderer for the response, before it is returned from the view.</p>
|
||||
<hr />
|
||||
<h1 id="creating-responses">Creating responses</h1>
|
||||
<h2 id="response">Response()</h2>
|
||||
<p><strong>Signature:</strong> <code>Response(data, status=None, template_name=None, headers=None, content_type=None)</code></p>
|
||||
<p>Unlike regular <code>HttpResponse</code> objects, you do not instantiate <code>Response</code> objects with rendered content. Instead you pass in unrendered data, which may consist of any Python primitives.</p>
|
||||
<p>The renderers used by the <code>Response</code> class cannot natively handle complex datatypes such as Django model instances, so you need to serialize the data into primitive datatypes before creating the <code>Response</code> object.</p>
|
||||
<p>You can use REST framework's <code>Serializer</code> classes to perform this data serialization, or use your own custom serialization.</p>
|
||||
<p>Arguments:</p>
|
||||
<ul>
|
||||
<li><code>data</code>: The serialized data for the response.</li>
|
||||
<li><code>status</code>: A status code for the response. Defaults to 200. See also <a href="status-codes.html">status codes</a>.</li>
|
||||
<li><code>template_name</code>: A template name to use if <code>HTMLRenderer</code> is selected.</li>
|
||||
<li><code>headers</code>: A dictionary of HTTP headers to use in the response.</li>
|
||||
<li><code>content_type</code>: The content type of the response. Typically, this will be set automatically by the renderer as determined by content negotiation, but there may be some cases where you need to specify the content type explicitly.</li>
|
||||
</ul>
|
||||
<hr />
|
||||
<h1 id="attributes">Attributes</h1>
|
||||
<h2 id="data">.data</h2>
|
||||
<p>The unrendered content of a <code>Request</code> object.</p>
|
||||
<h2 id="status_code">.status_code</h2>
|
||||
<p>The numeric status code of the HTTP response.</p>
|
||||
<h2 id="content">.content</h2>
|
||||
<p>The rendered content of the response. The <code>.render()</code> method must have been called before <code>.content</code> can be accessed.</p>
|
||||
<h2 id="template_name">.template_name</h2>
|
||||
<p>The <code>template_name</code>, if supplied. Only required if <code>HTMLRenderer</code> or some other custom template renderer is the accepted renderer for the response.</p>
|
||||
<h2 id="accepted_renderer">.accepted_renderer</h2>
|
||||
<p>The renderer instance that will be used to render the response.</p>
|
||||
<p>Set automatically by the <code>APIView</code> or <code>@api_view</code> immediately before the response is returned from the view.</p>
|
||||
<h2 id="accepted_media_type">.accepted_media_type</h2>
|
||||
<p>The media type that was selected by the content negotiation stage.</p>
|
||||
<p>Set automatically by the <code>APIView</code> or <code>@api_view</code> immediately before the response is returned from the view.</p>
|
||||
<h2 id="renderer_context">.renderer_context</h2>
|
||||
<p>A dictionary of additional context information that will be passed to the renderer's <code>.render()</code> method.</p>
|
||||
<p>Set automatically by the <code>APIView</code> or <code>@api_view</code> immediately before the response is returned from the view.</p>
|
||||
<hr />
|
||||
<h1 id="standard-httpresponse-attributes">Standard HttpResponse attributes</h1>
|
||||
<p>The <code>Response</code> class extends <code>SimpleTemplateResponse</code>, and all the usual attributes and methods are also available on the response. For example you can set headers on the response in the standard way:</p>
|
||||
<pre class="prettyprint lang-py"><code>response = Response()
|
||||
response['Cache-Control'] = 'no-cache'
|
||||
</code></pre>
|
||||
<h2 id="render">.render()</h2>
|
||||
<p><strong>Signature:</strong> <code>.render()</code></p>
|
||||
<p>As with any other <code>TemplateResponse</code>, this method is called to render the serialized data of the response into the final response content. When <code>.render()</code> is called, the response content will be set to the result of calling the <code>.render(data, accepted_media_type, renderer_context)</code> method on the <code>accepted_renderer</code> instance.</p>
|
||||
<p>You won't typically need to call <code>.render()</code> yourself, as it's handled by Django's standard response cycle.</p>
|
||||
</div><!--/span-->
|
||||
</div><!--/row-->
|
||||
</div><!--/.fluid-container-->
|
||||
</div><!--/.body content-->
|
||||
|
||||
<div id="push"></div>
|
||||
</div><!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a></p>
|
||||
</footer>
|
||||
|
||||
<!-- Le javascript
|
||||
================================================== -->
|
||||
<!-- Placed at the end of the document so the pages load faster -->
|
||||
<script src="http://django-rest-framework.org/js/jquery-1.8.1-min.js"></script>
|
||||
<script src="http://django-rest-framework.org/js/prettify-1.0.js"></script>
|
||||
<script src="http://django-rest-framework.org/js/bootstrap-2.1.1-min.js"></script>
|
||||
<script>
|
||||
//$('.side-nav').scrollspy()
|
||||
var shiftWindow = function() { scrollBy(0, -50) };
|
||||
if (location.hash) shiftWindow();
|
||||
window.addEventListener("hashchange", shiftWindow);
|
||||
|
||||
$('.dropdown-menu').on('click touchstart', function(event) {
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
// Dynamically force sidenav to no higher than browser window
|
||||
$('.side-nav').css('max-height', window.innerHeight - 130);
|
||||
|
||||
$(function(){
|
||||
$(window).resize(function(){
|
||||
$('.side-nav').css('max-height', window.innerHeight - 130);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body></html>
|
||||
279
api-guide/reverse.html
Normal file
279
api-guide/reverse.html
Normal file
|
|
@ -0,0 +1,279 @@
|
|||
<!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 - Returning URLs</title>
|
||||
<link href="http://django-rest-framework.org/img/favicon.ico" rel="icon" type="image/x-icon">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Django, API, REST, Returning URLs">
|
||||
<meta name="author" content="Tom Christie">
|
||||
|
||||
<!-- Le styles -->
|
||||
<link href="http://django-rest-framework.org/css/prettify.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/bootstrap.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/bootstrap-responsive.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/default.css" rel="stylesheet">
|
||||
|
||||
<!-- 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]-->
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-18852272-2']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="prettyPrint()" class="reverse-page">
|
||||
|
||||
<div class="wrapper">
|
||||
|
||||
<div class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container-fluid">
|
||||
<a class="repo-link btn btn-primary btn-small" href="https://github.com/tomchristie/django-rest-framework/tree/master">GitHub</a>
|
||||
<a class="repo-link btn btn-inverse btn-small " href="../api-guide/exceptions.html">Next <i class="icon-arrow-right icon-white"></i></a>
|
||||
<a class="repo-link btn btn-inverse btn-small " href="../api-guide/format-suffixes.html"><i class="icon-arrow-left icon-white"></i> Previous</a>
|
||||
<a class="repo-link btn btn-inverse btn-small" href="#searchModal" data-toggle="modal"><i class="icon-search icon-white"></i> Search</a>
|
||||
<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>
|
||||
<a class="brand" href="http://django-rest-framework.org">Django REST framework</a>
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav">
|
||||
<li><a href="http://django-rest-framework.org">Home</a></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Tutorial <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/tutorial/quickstart.html">Quickstart</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/1-serialization.html">1 - Serialization</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/2-requests-and-responses.html">2 - Requests and responses</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/3-class-based-views.html">3 - Class based views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/4-authentication-and-permissions.html">4 - Authentication and permissions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/5-relationships-and-hyperlinked-apis.html">5 - Relationships and hyperlinked APIs</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/6-viewsets-and-routers.html">6 - Viewsets and routers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">API Guide <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/api-guide/requests.html">Requests</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/responses.html">Responses</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/views.html">Views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/generic-views.html">Generic views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/viewsets.html">Viewsets</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/routers.html">Routers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/parsers.html">Parsers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/renderers.html">Renderers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/serializers.html">Serializers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/fields.html">Serializer fields</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/relations.html">Serializer relations</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/authentication.html">Authentication</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/permissions.html">Permissions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/throttling.html">Throttling</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/filtering.html">Filtering</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/pagination.html">Pagination</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/content-negotiation.html">Content negotiation</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/format-suffixes.html">Format suffixes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/reverse.html">Returning URLs</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/exceptions.html">Exceptions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/status-codes.html">Status codes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/testing.html">Testing</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/settings.html">Settings</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Topics <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/topics/documenting-your-api.html">Documenting your API</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/ajax-csrf-cors.html">AJAX, CSRF & CORS</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/browser-enhancements.html">Browser enhancements</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/browsable-api.html">The Browsable API</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/rest-hypermedia-hateoas.html">REST, Hypermedia & HATEOAS</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/rest-framework-2-announcement.html">2.0 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/2.2-announcement.html">2.2 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/2.3-announcement.html">2.3 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/release-notes.html">Release Notes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/credits.html">Credits</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="nav pull-right">
|
||||
<!-- TODO
|
||||
<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>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="body-content">
|
||||
<div class="container-fluid">
|
||||
|
||||
<!-- Search Modal -->
|
||||
<div id="searchModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3 id="myModalLabel">Documentation search</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<!-- Custom google search -->
|
||||
<script>
|
||||
(function() {
|
||||
var cx = '015016005043623903336:rxraeohqk6w';
|
||||
var gcse = document.createElement('script');
|
||||
gcse.type = 'text/javascript';
|
||||
gcse.async = true;
|
||||
gcse.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') +
|
||||
'//www.google.com/cse/cse.js?cx=' + cx;
|
||||
var s = document.getElementsByTagName('script')[0];
|
||||
s.parentNode.insertBefore(gcse, s);
|
||||
})();
|
||||
</script>
|
||||
<gcse:search></gcse:search>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row-fluid">
|
||||
|
||||
<div class="span3">
|
||||
<!-- TODO
|
||||
<p style="margin-top: -12px">
|
||||
<a class="btn btn-mini btn-primary" style="width: 60px">« previous</a>
|
||||
<a class="btn btn-mini btn-primary" style="float: right; margin-right: 8px; width: 60px;">next »</a>
|
||||
</p>
|
||||
-->
|
||||
<div id="table-of-contents">
|
||||
<ul class="nav nav-list side-nav well sidebar-nav-fixed">
|
||||
<li class="main"><a href="#returning-urls">Returning URLs</a></li>
|
||||
<li><a href="#reverse">reverse</a></li>
|
||||
<li><a href="#reverse_lazy">reverse_lazy</a></li>
|
||||
|
||||
<div>
|
||||
<hr>
|
||||
|
||||
<p><strong>The team behind REST framework are launching a new API service.</strong></p>
|
||||
|
||||
<p>If you want to be first in line when we start issuing invitations, please sign up here:</p>
|
||||
|
||||
<!-- Begin MailChimp Signup Form -->
|
||||
<link href="//cdn-images.mailchimp.com/embedcode/slim-081711.css" rel="stylesheet" type="text/css">
|
||||
<style type="text/css">
|
||||
#mc_embed_signup{background:#fff; clear:left; font:14px Helvetica,Arial,sans-serif; }
|
||||
/* Add your own MailChimp form style overrides in your site stylesheet or in this style block.
|
||||
We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
|
||||
</style>
|
||||
<div id="mc_embed_signup" style="background: rgb(245, 245, 245)">
|
||||
<form action="http://dabapps.us1.list-manage1.com/subscribe/post?u=cf73a9994eb5b8d8d461b5dfb&id=cb6af8e8bd" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>
|
||||
<!-- <label for="mce-EMAIL">Keep me posted!</label>
|
||||
--> <input style="width: 90%" type="email" value="" name="EMAIL" class="email" id="mce-EMAIL" placeholder="email address" required>
|
||||
<div class="clear"><input class="btn btn-success" type="submit" value="Yes, keep me posted!" name="subscribe" id="mc-embedded-subscribe" class="button"></div>
|
||||
</form>
|
||||
</div>
|
||||
</style></div>
|
||||
</ul>
|
||||
|
||||
|
||||
<!--End mc_embed_signup-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="main-content" class="span9">
|
||||
<p><a class="github" href="https://github.com/tomchristie/django-rest-framework/tree/master/rest_framework/reverse.py"><span class="label label-info">reverse.py</span></a></p>
|
||||
<h1 id="returning-urls">Returning URLs</h1>
|
||||
<blockquote>
|
||||
<p>The central feature that distinguishes the REST architectural style from other network-based styles is its emphasis on a uniform interface between components.</p>
|
||||
<p>— Roy Fielding, <a href="http://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_1_5">Architectural Styles and the Design of Network-based Software Architectures</a></p>
|
||||
</blockquote>
|
||||
<p>As a rule, it's probably better practice to return absolute URIs from your Web APIs, such as <code>http://example.com/foobar</code>, rather than returning relative URIs, such as <code>/foobar</code>.</p>
|
||||
<p>The advantages of doing so are:</p>
|
||||
<ul>
|
||||
<li>It's more explicit.</li>
|
||||
<li>It leaves less work for your API clients.</li>
|
||||
<li>There's no ambiguity about the meaning of the string when it's found in representations such as JSON that do not have a native URI type.</li>
|
||||
<li>It makes it easy to do things like markup HTML representations with hyperlinks.</li>
|
||||
</ul>
|
||||
<p>REST framework provides two utility functions to make it more simple to return absolute URIs from your Web API.</p>
|
||||
<p>There's no requirement for you to use them, but if you do then the self-describing API will be able to automatically hyperlink its output for you, which makes browsing the API much easier.</p>
|
||||
<h2 id="reverse">reverse</h2>
|
||||
<p><strong>Signature:</strong> <code>reverse(viewname, *args, **kwargs)</code></p>
|
||||
<p>Has the same behavior as <a href="https://docs.djangoproject.com/en/dev/topics/http/urls/#reverse"><code>django.core.urlresolvers.reverse</code></a>, except that it returns a fully qualified URL, using the request to determine the host and port.</p>
|
||||
<p>You should <strong>include the request as a keyword argument</strong> to the function, for example:</p>
|
||||
<pre class="prettyprint lang-py"><code>from rest_framework.reverse import reverse
|
||||
from rest_framework.views import APIView
|
||||
from django.utils.timezone import now
|
||||
|
||||
class APIRootView(APIView):
|
||||
def get(self, request):
|
||||
year = now().year
|
||||
data = {
|
||||
...
|
||||
'year-summary-url': reverse('year-summary', args=[year], request=request)
|
||||
}
|
||||
return Response(data)
|
||||
</code></pre>
|
||||
<h2 id="reverse_lazy">reverse_lazy</h2>
|
||||
<p><strong>Signature:</strong> <code>reverse_lazy(viewname, *args, **kwargs)</code></p>
|
||||
<p>Has the same behavior as <a href="https://docs.djangoproject.com/en/dev/topics/http/urls/#reverse-lazy"><code>django.core.urlresolvers.reverse_lazy</code></a>, except that it returns a fully qualified URL, using the request to determine the host and port.</p>
|
||||
<p>As with the <code>reverse</code> function, you should <strong>include the request as a keyword argument</strong> to the function, for example:</p>
|
||||
<pre class="prettyprint lang-py"><code>api_root = reverse_lazy('api-root', request=request)
|
||||
</code></pre>
|
||||
</div><!--/span-->
|
||||
</div><!--/row-->
|
||||
</div><!--/.fluid-container-->
|
||||
</div><!--/.body content-->
|
||||
|
||||
<div id="push"></div>
|
||||
</div><!--/.wrapper -->
|
||||
|
||||
<footer class="span12">
|
||||
<p>Sponsored by <a href="http://dabapps.com/">DabApps</a>.</a></p>
|
||||
</footer>
|
||||
|
||||
<!-- Le javascript
|
||||
================================================== -->
|
||||
<!-- Placed at the end of the document so the pages load faster -->
|
||||
<script src="http://django-rest-framework.org/js/jquery-1.8.1-min.js"></script>
|
||||
<script src="http://django-rest-framework.org/js/prettify-1.0.js"></script>
|
||||
<script src="http://django-rest-framework.org/js/bootstrap-2.1.1-min.js"></script>
|
||||
<script>
|
||||
//$('.side-nav').scrollspy()
|
||||
var shiftWindow = function() { scrollBy(0, -50) };
|
||||
if (location.hash) shiftWindow();
|
||||
window.addEventListener("hashchange", shiftWindow);
|
||||
|
||||
$('.dropdown-menu').on('click touchstart', function(event) {
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
// Dynamically force sidenav to no higher than browser window
|
||||
$('.side-nav').css('max-height', window.innerHeight - 130);
|
||||
|
||||
$(function(){
|
||||
$(window).resize(function(){
|
||||
$('.side-nav').css('max-height', window.innerHeight - 130);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body></html>
|
||||
369
api-guide/routers.html
Normal file
369
api-guide/routers.html
Normal file
|
|
@ -0,0 +1,369 @@
|
|||
<!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 - Routers</title>
|
||||
<link href="http://django-rest-framework.org/img/favicon.ico" rel="icon" type="image/x-icon">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="description" content="Django, API, REST, Routers, API Guide, Custom Routers">
|
||||
<meta name="author" content="Tom Christie">
|
||||
|
||||
<!-- Le styles -->
|
||||
<link href="http://django-rest-framework.org/css/prettify.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/bootstrap.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/bootstrap-responsive.css" rel="stylesheet">
|
||||
<link href="http://django-rest-framework.org/css/default.css" rel="stylesheet">
|
||||
|
||||
<!-- 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]-->
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var _gaq = _gaq || [];
|
||||
_gaq.push(['_setAccount', 'UA-18852272-2']);
|
||||
_gaq.push(['_trackPageview']);
|
||||
|
||||
(function() {
|
||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
||||
})();
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="prettyPrint()" class="routers-page">
|
||||
|
||||
<div class="wrapper">
|
||||
|
||||
<div class="navbar navbar-inverse navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container-fluid">
|
||||
<a class="repo-link btn btn-primary btn-small" href="https://github.com/tomchristie/django-rest-framework/tree/master">GitHub</a>
|
||||
<a class="repo-link btn btn-inverse btn-small " href="../api-guide/parsers.html">Next <i class="icon-arrow-right icon-white"></i></a>
|
||||
<a class="repo-link btn btn-inverse btn-small " href="../api-guide/viewsets.html"><i class="icon-arrow-left icon-white"></i> Previous</a>
|
||||
<a class="repo-link btn btn-inverse btn-small" href="#searchModal" data-toggle="modal"><i class="icon-search icon-white"></i> Search</a>
|
||||
<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>
|
||||
<a class="brand" href="http://django-rest-framework.org">Django REST framework</a>
|
||||
<div class="nav-collapse collapse">
|
||||
<ul class="nav">
|
||||
<li><a href="http://django-rest-framework.org">Home</a></li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Tutorial <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/tutorial/quickstart.html">Quickstart</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/1-serialization.html">1 - Serialization</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/2-requests-and-responses.html">2 - Requests and responses</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/3-class-based-views.html">3 - Class based views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/4-authentication-and-permissions.html">4 - Authentication and permissions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/5-relationships-and-hyperlinked-apis.html">5 - Relationships and hyperlinked APIs</a></li>
|
||||
<li><a href="http://django-rest-framework.org/tutorial/6-viewsets-and-routers.html">6 - Viewsets and routers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">API Guide <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/api-guide/requests.html">Requests</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/responses.html">Responses</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/views.html">Views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/generic-views.html">Generic views</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/viewsets.html">Viewsets</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/routers.html">Routers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/parsers.html">Parsers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/renderers.html">Renderers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/serializers.html">Serializers</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/fields.html">Serializer fields</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/relations.html">Serializer relations</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/authentication.html">Authentication</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/permissions.html">Permissions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/throttling.html">Throttling</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/filtering.html">Filtering</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/pagination.html">Pagination</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/content-negotiation.html">Content negotiation</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/format-suffixes.html">Format suffixes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/reverse.html">Returning URLs</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/exceptions.html">Exceptions</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/status-codes.html">Status codes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/testing.html">Testing</a></li>
|
||||
<li><a href="http://django-rest-framework.org/api-guide/settings.html">Settings</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Topics <b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://django-rest-framework.org/topics/documenting-your-api.html">Documenting your API</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/ajax-csrf-cors.html">AJAX, CSRF & CORS</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/browser-enhancements.html">Browser enhancements</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/browsable-api.html">The Browsable API</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/rest-hypermedia-hateoas.html">REST, Hypermedia & HATEOAS</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/rest-framework-2-announcement.html">2.0 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/2.2-announcement.html">2.2 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/2.3-announcement.html">2.3 Announcement</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/release-notes.html">Release Notes</a></li>
|
||||
<li><a href="http://django-rest-framework.org/topics/credits.html">Credits</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="nav pull-right">
|
||||
<!-- TODO
|
||||
<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>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="body-content">
|
||||
<div class="container-fluid">
|
||||
|
||||
<!-- Search Modal -->
|
||||
<div id="searchModal" class="modal hide fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3 id="myModalLabel">Documentation search</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<!-- Custom google search -->
|
||||
<script>
|
||||
(function() {
|
||||
var cx = '015016005043623903336:rxraeohqk6w';
|
||||
var gcse = document.createElement('script');
|
||||
gcse.type = 'text/javascript';
|
||||