aboutsummaryrefslogtreecommitdiffstats
path: root/api-guide
diff options
context:
space:
mode:
Diffstat (limited to 'api-guide')
-rw-r--r--api-guide/authentication/index.html147
-rw-r--r--api-guide/content-negotiation/index.html30
-rw-r--r--api-guide/exceptions/index.html51
-rw-r--r--api-guide/fields/index.html31
-rw-r--r--api-guide/filtering/index.html28
-rw-r--r--api-guide/format-suffixes/index.html28
-rw-r--r--api-guide/generic-views/index.html34
-rw-r--r--api-guide/metadata/index.html28
-rw-r--r--api-guide/pagination/index.html381
-rw-r--r--api-guide/parsers/index.html102
-rw-r--r--api-guide/permissions/index.html42
-rw-r--r--api-guide/relations/index.html28
-rw-r--r--api-guide/renderers/index.html156
-rw-r--r--api-guide/requests/index.html30
-rw-r--r--api-guide/responses/index.html28
-rw-r--r--api-guide/reverse/index.html28
-rw-r--r--api-guide/routers/index.html28
-rw-r--r--api-guide/serializers/index.html81
-rw-r--r--api-guide/settings/index.html49
-rw-r--r--api-guide/status-codes/index.html28
-rw-r--r--api-guide/testing/index.html42
-rw-r--r--api-guide/throttling/index.html28
-rw-r--r--api-guide/validators/index.html28
-rw-r--r--api-guide/versioning/index.html612
-rw-r--r--api-guide/views/index.html28
-rw-r--r--api-guide/viewsets/index.html30
26 files changed, 1364 insertions, 762 deletions
diff --git a/api-guide/authentication/index.html b/api-guide/authentication/index.html
index 7a523c63..bf304897 100644
--- a/api-guide/authentication/index.html
+++ b/api-guide/authentication/index.html
@@ -189,6 +189,10 @@
</li>
<li >
+ <a href="../versioning">Versioning</a>
+ </li>
+
+ <li >
<a href="../content-negotiation">Content negotiation</a>
</li>
@@ -232,6 +236,10 @@
</li>
<li >
+ <a href="../../topics/internationalization">Internationalization</a>
+ </li>
+
+ <li >
<a href="../../topics/ajax-csrf-cors">AJAX, CSRF & CORS</a>
</li>
@@ -260,23 +268,11 @@
</li>
<li >
- <a href="../../topics/rest-framework-2-announcement">2.0 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.2-announcement">2.2 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.3-announcement">2.3 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.4-announcement">2.4 Announcement</a>
+ <a href="../../topics/3.0-announcement">3.0 Announcement</a>
</li>
<li >
- <a href="../../topics/3.0-announcement">3.0 Announcement</a>
+ <a href="../../topics/3.1-announcement">3.1 Announcement</a>
</li>
<li >
@@ -287,10 +283,6 @@
<a href="../../topics/release-notes">Release Notes</a>
</li>
- <li >
- <a href="../../topics/credits">Credits</a>
- </li>
-
</ul>
</li>
@@ -393,14 +385,6 @@
<a href="#sessionauthentication">SessionAuthentication</a>
</li>
- <li>
- <a href="#oauthauthentication">OAuthAuthentication</a>
- </li>
-
- <li>
- <a href="#oauth2authentication">OAuth2Authentication</a>
- </li>
-
@@ -422,11 +406,15 @@
<li>
- <a href="#digest-authentication">Digest Authentication</a>
+ <a href="#django-oauth-toolkit">Django OAuth Toolkit</a>
</li>
<li>
- <a href="#django-oauth-toolkit">Django OAuth Toolkit</a>
+ <a href="#django-rest-framework-oauth">Django REST framework OAuth</a>
+ </li>
+
+ <li>
+ <a href="#digest-authentication">Digest Authentication</a>
</li>
<li>
@@ -449,6 +437,10 @@
<a href="#djoser">Djoser</a>
</li>
+ <li>
+ <a href="#django-rest-auth">django-rest-auth</a>
+ </li>
+
@@ -649,74 +641,6 @@ python manage.py createsuperuser
</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/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><code>INSTALLED_APPS = (
- ...
- `oauth_provider`,
-)
-</code></pre>
-<p>Don't forget to run <code>syncdb</code> once you've added the package.</p>
-<pre><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><code>INSTALLED_APPS = (
- ...
- 'provider',
- 'provider.oauth2',
-)
-</code></pre>
-<p>Then add <code>OAuth2Authentication</code> to your global <code>DEFAULT_AUTHENTICATION_CLASSES</code> setting:</p>
-<pre><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><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><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><code>curl -X POST -d "client_id=YOUR_CLIENT_ID&amp;client_secret=YOUR_CLIENT_SECRET&amp;grant_type=password&amp;username=YOUR_USERNAME&amp;password=YOUR_PASSWORD" http://localhost:8000/oauth2/access_token/
-</code></pre>
-<p>You should get a response that looks something like this:</p>
-<pre><code>{"access_token": "&lt;your-access-token&gt;", "scope": "read", "expires_in": 86399, "refresh_token": "&lt;your-refresh-token&gt;"}
-</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><code>curl -H "Authorization: Bearer &lt;your-access-token&gt;" 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>
@@ -749,10 +673,35 @@ class ExampleAuthentication(authentication.BaseAuthentication):
<hr />
<h1 id="third-party-packages">Third party packages</h1>
<p>The following third party packages are also available.</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 excellent <a href="https://github.com/idan/oauthlib">OAuthLib</a>. The package is well documented, and well supported and is currently our <strong>recommended package for OAuth 2.0 support</strong>.</p>
+<h4 id="installation-configuration">Installation &amp; configuration</h4>
+<p>Install using <code>pip</code>.</p>
+<pre><code>pip install django-oauth-toolkit
+</code></pre>
+<p>Add the package to your <code>INSTALLED_APPS</code> and modify your REST framework settings.</p>
+<pre><code>INSTALLED_APPS = (
+ ...
+ 'oauth2_provider',
+)
+
+REST_FRAMEWORK = {
+ 'DEFAULT_AUTHENTICATION_CLASSES': (
+ 'oauth2_provider.ext.rest_framework.OAuth2Authentication',
+ )
+}
+</code></pre>
+<p>For more details see the <a href="https://django-oauth-toolkit.readthedocs.org/en/latest/rest-framework/getting_started.html">Django REST framework - Getting started</a> documentation.</p>
+<h2 id="django-rest-framework-oauth">Django REST framework OAuth</h2>
+<p>The <a href="http://jpadilla.github.io/django-rest-framework-oauth/">Django REST framework OAuth</a> package provides both OAuth1 and OAuth2 support for REST framework.</p>
+<p>This package was previously included directly in REST framework but is now supported and maintained as a third party package.</p>
+<h4 id="installation-configuration_1">Installation &amp; configuration</h4>
+<p>Install the package using <code>pip</code>.</p>
+<pre><code>pip install djangorestframework-oauth
+</code></pre>
+<p>For details on configuration and usage see the Django REST framework OAuth documentation for <a href="http://jpadilla.github.io/django-rest-framework-oauth/authentication/">authentication</a> and <a href="http://jpadilla.github.io/django-rest-framework-oauth/permissions/">permissions</a>.</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 excellent <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>
<h2 id="json-web-token-authentication">JSON Web Token Authentication</h2>
@@ -763,6 +712,8 @@ class ExampleAuthentication(authentication.BaseAuthentication):
<p>HTTP Signature (currently a <a href="https://datatracker.ietf.org/doc/draft-cavage-http-signatures/">IETF draft</a>) provides a way to achieve origin authentication and message integrity for HTTP messages. Similar to <a href="http://docs.aws.amazon.com/general/latest/gr/signature-version-4.html">Amazon's HTTP Signature scheme</a>, used by many of its services, it permits stateless, per-request authentication. <a href="https://github.com/etoccalino/">Elvio Toccalino</a> maintains the <a href="https://github.com/etoccalino/django-rest-framework-httpsignature">djangorestframework-httpsignature</a> package which provides an easy to use HTTP Signature Authentication mechanism.</p>
<h2 id="djoser">Djoser</h2>
<p><a href="https://github.com/sunscrapers/djoser">Djoser</a> library provides a set of views to handle basic actions such as registration, login, logout, password reset and account activation. The package works with a custom user model and it uses token based authentication. This is a ready to use REST implementation of Django authentication system.</p>
+<h2 id="django-rest-auth">django-rest-auth</h2>
+<p><a href="https://github.com/Tivix/django-rest-auth">Django-rest-auth</a> library provides a set of REST API endpoints for registration, authentication (including social media authentication), password reset, retrieve and update user details, etc. By having these API endpoints, your client apps such as AngularJS, iOS, Android, and others can communicate to your Django backend site independently via REST APIs for user management.</p>
</div>
<!--/span-->
diff --git a/api-guide/content-negotiation/index.html b/api-guide/content-negotiation/index.html
index fcc0ff3a..ebde1d6b 100644
--- a/api-guide/content-negotiation/index.html
+++ b/api-guide/content-negotiation/index.html
@@ -65,7 +65,7 @@
<a class="repo-link btn btn-inverse btn-small " rel="prev" href="../metadata">
Next <i class="icon-arrow-right icon-white"></i>
</a>
- <a class="repo-link btn btn-inverse btn-small " rel="next" href="../pagination">
+ <a class="repo-link btn btn-inverse btn-small " rel="next" href="../versioning">
<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>
@@ -188,6 +188,10 @@
<a href="../pagination">Pagination</a>
</li>
+ <li >
+ <a href="../versioning">Versioning</a>
+ </li>
+
<li class="active" >
<a href=".">Content negotiation</a>
</li>
@@ -232,6 +236,10 @@
</li>
<li >
+ <a href="../../topics/internationalization">Internationalization</a>
+ </li>
+
+ <li >
<a href="../../topics/ajax-csrf-cors">AJAX, CSRF & CORS</a>
</li>
@@ -260,23 +268,11 @@
</li>
<li >
- <a href="../../topics/rest-framework-2-announcement">2.0 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.2-announcement">2.2 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.3-announcement">2.3 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.4-announcement">2.4 Announcement</a>
+ <a href="../../topics/3.0-announcement">3.0 Announcement</a>
</li>
<li >
- <a href="../../topics/3.0-announcement">3.0 Announcement</a>
+ <a href="../../topics/3.1-announcement">3.1 Announcement</a>
</li>
<li >
@@ -287,10 +283,6 @@
<a href="../../topics/release-notes">Release Notes</a>
</li>
- <li >
- <a href="../../topics/credits">Credits</a>
- </li>
-
</ul>
</li>
diff --git a/api-guide/exceptions/index.html b/api-guide/exceptions/index.html
index f9403f1d..c0ddeb4f 100644
--- a/api-guide/exceptions/index.html
+++ b/api-guide/exceptions/index.html
@@ -189,6 +189,10 @@
</li>
<li >
+ <a href="../versioning">Versioning</a>
+ </li>
+
+ <li >
<a href="../content-negotiation">Content negotiation</a>
</li>
@@ -232,6 +236,10 @@
</li>
<li >
+ <a href="../../topics/internationalization">Internationalization</a>
+ </li>
+
+ <li >
<a href="../../topics/ajax-csrf-cors">AJAX, CSRF & CORS</a>
</li>
@@ -260,23 +268,11 @@
</li>
<li >
- <a href="../../topics/rest-framework-2-announcement">2.0 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.2-announcement">2.2 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.3-announcement">2.3 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.4-announcement">2.4 Announcement</a>
+ <a href="../../topics/3.0-announcement">3.0 Announcement</a>
</li>
<li >
- <a href="../../topics/3.0-announcement">3.0 Announcement</a>
+ <a href="../../topics/3.1-announcement">3.1 Announcement</a>
</li>
<li >
@@ -287,10 +283,6 @@
<a href="../../topics/release-notes">Release Notes</a>
</li>
- <li >
- <a href="../../topics/credits">Credits</a>
- </li>
-
</ul>
</li>
@@ -394,10 +386,18 @@
</li>
<li>
+ <a href="#notfound">NotFound</a>
+ </li>
+
+ <li>
<a href="#methodnotallowed">MethodNotAllowed</a>
</li>
<li>
+ <a href="#notacceptable">NotAcceptable</a>
+ </li>
+
+ <li>
<a href="#unsupportedmediatype">UnsupportedMediaType</a>
</li>
@@ -464,7 +464,7 @@ Content-Length: 94
</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>The function must take a pair of arguments, this first is the exception to be handled, and the second is a dictionary containing any extra context such as the view currently being handled. The exception handler function 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><code>HTTP/1.1 405 Method Not Allowed
Content-Type: application/json
@@ -475,10 +475,10 @@ Content-Length: 62
<p>In order to alter the style of the response, you could write the following custom exception handler:</p>
<pre><code>from rest_framework.views import exception_handler
-def custom_exception_handler(exc):
+def custom_exception_handler(exc, context):
# Call REST framework's default exception handler first,
# to get the standard error response.
- response = exception_handler(exc)
+ response = exception_handler(exc, context)
# Now add the HTTP status code to the response.
if response is not None:
@@ -486,6 +486,7 @@ def custom_exception_handler(exc):
return response
</code></pre>
+<p>The context argument is not used by the default handler, but can be useful if the exception handler needs further information such as the view currently being handled, which can be accessed as <code>context['view']</code>.</p>
<p>The exception handler must also be configured in your settings, using the <code>EXCEPTION_HANDLER</code> setting key. For example:</p>
<pre><code>REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'my_project.my_app.utils.custom_exception_handler'
@@ -526,10 +527,18 @@ class ServiceUnavailable(APIException):
<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="notfound">NotFound</h2>
+<p><strong>Signature:</strong> <code>NotFound(detail=None)</code></p>
+<p>Raised when a resource does not exists at the given URL. This exception is equivalent to the standard <code>Http404</code> Django exception.</p>
+<p>By default this exception results in a response with the HTTP status code "404 Not Found".</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="notacceptable">NotAcceptable</h2>
+<p><strong>Signature:</strong> <code>NotAcceptable(detail=None)</code></p>
+<p>Raised when an incoming request occurs with an <code>Accept</code> header that cannot be satisfied by any of the available renderers.</p>
+<p>By default this exception results in a response with the HTTP status code "406 Not Acceptable".</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>.</p>
diff --git a/api-guide/fields/index.html b/api-guide/fields/index.html
index 9fd73553..1b7019fe 100644
--- a/api-guide/fields/index.html
+++ b/api-guide/fields/index.html
@@ -189,6 +189,10 @@
</li>
<li >
+ <a href="../versioning">Versioning</a>
+ </li>
+
+ <li >
<a href="../content-negotiation">Content negotiation</a>
</li>
@@ -232,6 +236,10 @@
</li>
<li >
+ <a href="../../topics/internationalization">Internationalization</a>
+ </li>
+
+ <li >
<a href="../../topics/ajax-csrf-cors">AJAX, CSRF & CORS</a>
</li>
@@ -260,23 +268,11 @@
</li>
<li >
- <a href="../../topics/rest-framework-2-announcement">2.0 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.2-announcement">2.2 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.3-announcement">2.3 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.4-announcement">2.4 Announcement</a>
+ <a href="../../topics/3.0-announcement">3.0 Announcement</a>
</li>
<li >
- <a href="../../topics/3.0-announcement">3.0 Announcement</a>
+ <a href="../../topics/3.1-announcement">3.1 Announcement</a>
</li>
<li >
@@ -287,10 +283,6 @@
<a href="../../topics/release-notes">Release Notes</a>
</li>
- <li >
- <a href="../../topics/credits">Credits</a>
- </li>
-
</ul>
</li>
@@ -661,11 +653,12 @@ color_channel = serializers.ChoiceField(
<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, allow_blank=False)</code></p>
+<p><strong>Signature:</strong> <code>CharField(max_length=None, min_length=None, allow_blank=False, trim_whitespace=True)</code></p>
<ul>
<li><code>max_length</code> - Validates that the input contains no more than this number of characters.</li>
<li><code>min_length</code> - Validates that the input contains no fewer than this number of characters.</li>
<li><code>allow_blank</code> - If set to <code>True</code> then the empty string should be considered a valid value. If set to <code>False</code> then the empty string is considered invalid and will raise a validation error. Defaults to <code>False</code>.</li>
+<li><code>trim_whitespace</code> - If set to <code>True</code> then leading and trailing whitespace is trimmed. Defaults to <code>True</code>.</li>
</ul>
<p>The <code>allow_null</code> option is also available for string fields, although its usage is discouraged in favor of <code>allow_blank</code>. It is valid to set both <code>allow_blank=True</code> and <code>allow_null=True</code>, but doing so means that there will be two differing types of empty value permissible for string representations, which can lead to data inconsistencies and subtle application bugs.</p>
<h2 id="emailfield">EmailField</h2>
diff --git a/api-guide/filtering/index.html b/api-guide/filtering/index.html
index 7cf57f6b..fc8dafb2 100644
--- a/api-guide/filtering/index.html
+++ b/api-guide/filtering/index.html
@@ -189,6 +189,10 @@
</li>
<li >
+ <a href="../versioning">Versioning</a>
+ </li>
+
+ <li >
<a href="../content-negotiation">Content negotiation</a>
</li>
@@ -232,6 +236,10 @@
</li>
<li >
+ <a href="../../topics/internationalization">Internationalization</a>
+ </li>
+
+ <li >
<a href="../../topics/ajax-csrf-cors">AJAX, CSRF & CORS</a>
</li>
@@ -260,23 +268,11 @@
</li>
<li >
- <a href="../../topics/rest-framework-2-announcement">2.0 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.2-announcement">2.2 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.3-announcement">2.3 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.4-announcement">2.4 Announcement</a>
+ <a href="../../topics/3.0-announcement">3.0 Announcement</a>
</li>
<li >
- <a href="../../topics/3.0-announcement">3.0 Announcement</a>
+ <a href="../../topics/3.1-announcement">3.1 Announcement</a>
</li>
<li >
@@ -287,10 +283,6 @@
<a href="../../topics/release-notes">Release Notes</a>
</li>
- <li >
- <a href="../../topics/credits">Credits</a>
- </li>
-
</ul>
</li>
diff --git a/api-guide/format-suffixes/index.html b/api-guide/format-suffixes/index.html
index d7d74db9..a01438d8 100644
--- a/api-guide/format-suffixes/index.html
+++ b/api-guide/format-suffixes/index.html
@@ -189,6 +189,10 @@
</li>
<li >
+ <a href="../versioning">Versioning</a>
+ </li>
+
+ <li >
<a href="../content-negotiation">Content negotiation</a>
</li>
@@ -232,6 +236,10 @@
</li>
<li >
+ <a href="../../topics/internationalization">Internationalization</a>
+ </li>
+
+ <li >
<a href="../../topics/ajax-csrf-cors">AJAX, CSRF & CORS</a>
</li>
@@ -260,23 +268,11 @@
</li>
<li >
- <a href="../../topics/rest-framework-2-announcement">2.0 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.2-announcement">2.2 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.3-announcement">2.3 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.4-announcement">2.4 Announcement</a>
+ <a href="../../topics/3.0-announcement">3.0 Announcement</a>
</li>
<li >
- <a href="../../topics/3.0-announcement">3.0 Announcement</a>
+ <a href="../../topics/3.1-announcement">3.1 Announcement</a>
</li>
<li >
@@ -287,10 +283,6 @@
<a href="../../topics/release-notes">Release Notes</a>
</li>
- <li >
- <a href="../../topics/credits">Credits</a>
- </li>
-
</ul>
</li>
diff --git a/api-guide/generic-views/index.html b/api-guide/generic-views/index.html
index 082f0bb0..288a7115 100644
--- a/api-guide/generic-views/index.html
+++ b/api-guide/generic-views/index.html
@@ -189,6 +189,10 @@
</li>
<li >
+ <a href="../versioning">Versioning</a>
+ </li>
+
+ <li >
<a href="../content-negotiation">Content negotiation</a>
</li>
@@ -232,6 +236,10 @@
</li>
<li >
+ <a href="../../topics/internationalization">Internationalization</a>
+ </li>
+
+ <li >
<a href="../../topics/ajax-csrf-cors">AJAX, CSRF & CORS</a>
</li>
@@ -260,23 +268,11 @@
</li>
<li >
- <a href="../../topics/rest-framework-2-announcement">2.0 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.2-announcement">2.2 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.3-announcement">2.3 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.4-announcement">2.4 Announcement</a>
+ <a href="../../topics/3.0-announcement">3.0 Announcement</a>
</li>
<li >
- <a href="../../topics/3.0-announcement">3.0 Announcement</a>
+ <a href="../../topics/3.1-announcement">3.1 Announcement</a>
</li>
<li >
@@ -287,10 +283,6 @@
<a href="../../topics/release-notes">Release Notes</a>
</li>
- <li >
- <a href="../../topics/credits">Credits</a>
- </li>
-
</ul>
</li>
@@ -568,11 +560,9 @@ class UserList(generics.ListCreateAPIView):
<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>
+<li><code>pagination_class</code> - The pagination class that should be used when paginating list results. Defaults to the same value as the <code>DEFAULT_PAGINATION_CLASS</code> setting, which is <code>'rest_framework.pagination.PageNumberPagination'</code>.</li>
</ul>
+<p>Note that usage of the <code>paginate_by</code>, <code>paginate_by_param</code> and <code>page_kwarg</code> attributes are now pending deprecation. The <code>pagination_serializer_class</code> attribute and <code>DEFAULT_PAGINATION_SERIALIZER_CLASS</code> setting have been removed completely. Pagination settings should instead be controlled by overriding a pagination class and setting any configuration attributes there. See the pagination documentation for more details.</p>
<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>
diff --git a/api-guide/metadata/index.html b/api-guide/metadata/index.html
index 909bdcf4..9d30200e 100644
--- a/api-guide/metadata/index.html
+++ b/api-guide/metadata/index.html
@@ -189,6 +189,10 @@
</li>
<li >
+ <a href="../versioning">Versioning</a>
+ </li>
+
+ <li >
<a href="../content-negotiation">Content negotiation</a>
</li>
@@ -232,6 +236,10 @@
</li>
<li >
+ <a href="../../topics/internationalization">Internationalization</a>
+ </li>
+
+ <li >
<a href="../../topics/ajax-csrf-cors">AJAX, CSRF & CORS</a>
</li>
@@ -260,23 +268,11 @@
</li>
<li >
- <a href="../../topics/rest-framework-2-announcement">2.0 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.2-announcement">2.2 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.3-announcement">2.3 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.4-announcement">2.4 Announcement</a>
+ <a href="../../topics/3.0-announcement">3.0 Announcement</a>
</li>
<li >
- <a href="../../topics/3.0-announcement">3.0 Announcement</a>
+ <a href="../../topics/3.1-announcement">3.1 Announcement</a>
</li>
<li >
@@ -287,10 +283,6 @@
<a href="../../topics/release-notes">Release Notes</a>
</li>
- <li >
- <a href="../../topics/credits">Credits</a>
- </li>
-
</ul>
</li>
diff --git a/api-guide/pagination/index.html b/api-guide/pagination/index.html
index 5e8f2a82..37cb383e 100644
--- a/api-guide/pagination/index.html
+++ b/api-guide/pagination/index.html
@@ -62,7 +62,7 @@
<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 " rel="prev" href="../content-negotiation">
+ <a class="repo-link btn btn-inverse btn-small " rel="prev" href="../versioning">
Next <i class="icon-arrow-right icon-white"></i>
</a>
<a class="repo-link btn btn-inverse btn-small " rel="next" href="../filtering">
@@ -189,6 +189,10 @@
</li>
<li >
+ <a href="../versioning">Versioning</a>
+ </li>
+
+ <li >
<a href="../content-negotiation">Content negotiation</a>
</li>
@@ -232,6 +236,10 @@
</li>
<li >
+ <a href="../../topics/internationalization">Internationalization</a>
+ </li>
+
+ <li >
<a href="../../topics/ajax-csrf-cors">AJAX, CSRF & CORS</a>
</li>
@@ -260,23 +268,11 @@
</li>
<li >
- <a href="../../topics/rest-framework-2-announcement">2.0 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.2-announcement">2.2 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.3-announcement">2.3 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.4-announcement">2.4 Announcement</a>
+ <a href="../../topics/3.0-announcement">3.0 Announcement</a>
</li>
<li >
- <a href="../../topics/3.0-announcement">3.0 Announcement</a>
+ <a href="../../topics/3.1-announcement">3.1 Announcement</a>
</li>
<li >
@@ -287,10 +283,6 @@
<a href="../../topics/release-notes">Release Notes</a>
</li>
- <li >
- <a href="../../topics/credits">Credits</a>
- </li>
-
</ul>
</li>
@@ -358,22 +350,38 @@
<li>
- <a href="#paginating-basic-data">Paginating basic data</a>
+ <a href="#setting-the-pagination-style">Setting the pagination style</a>
+ </li>
+
+ <li>
+ <a href="#modifying-the-pagination-style">Modifying the pagination style</a>
+ </li>
+
+
+
+
+ <li class="main">
+ <a href="#api-reference">API Reference</a>
+ </li>
+
+
+ <li>
+ <a href="#pagenumberpagination">PageNumberPagination</a>
</li>
<li>
- <a href="#paginating-querysets">Paginating QuerySets</a>
+ <a href="#limitoffsetpagination">LimitOffsetPagination</a>
</li>
<li>
- <a href="#pagination-in-the-generic-views">Pagination in the generic views</a>
+ <a href="#cursorpagination">CursorPagination</a>
</li>
<li class="main">
- <a href="#custom-pagination-serializers">Custom pagination serializers</a>
+ <a href="#custom-pagination-styles">Custom pagination styles</a>
</li>
@@ -382,7 +390,23 @@
</li>
<li>
- <a href="#using-your-custom-pagination-serializer">Using your custom pagination serializer</a>
+ <a href="#header-based-pagination">Header based pagination</a>
+ </li>
+
+ <li>
+ <a href="#using-your-custom-pagination-class">Using your custom pagination class</a>
+ </li>
+
+
+
+
+ <li class="main">
+ <a href="#html-pagination-controls">HTML pagination controls</a>
+ </li>
+
+
+ <li>
+ <a href="#customizing-the-controls">Customizing the controls</a>
</li>
@@ -421,123 +445,230 @@
<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>&mdash; <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><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']
+<p>REST framework includes support for customizable pagination styles. This allows you to modify how large result sets are split into individual pages of data.</p>
+<p>The pagination API can support either:</p>
+<ul>
+<li>Pagination links that are provided as part of the content of the response.</li>
+<li>Pagination links that are included in response headers, such as <code>Content-Range</code> or <code>Link</code>.</li>
+</ul>
+<p>The built-in styles currently all use links included as part of the content of the response. This style is more accessible when using the browsable API.</p>
+<p>Pagination is only performed automatically if you're using the generic views or viewsets. If you're using a regular <code>APIView</code>, you'll need to call into the pagination API yourself to ensure you return a paginated response. See the source code for the <code>mixins.ListMixin</code> and <code>generics.GenericAPIView</code> classes for an example.</p>
+<h2 id="setting-the-pagination-style">Setting the pagination style</h2>
+<p>The default pagination style may be set globally, using the <code>DEFAULT_PAGINATION_CLASS</code> settings key. For example, to use the built-in limit/offset pagination, you would do:</p>
+<pre><code>REST_FRAMEWORK = {
+ 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination'
+}
</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><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']}
+<p>You can also set the pagination class on an individual view by using the <code>pagination_class</code> attribute. Typically you'll want to use the same pagination style throughout your API, although you might want to vary individual aspects of the pagination, such as default or maximum page size, on a per-view basis.</p>
+<h2 id="modifying-the-pagination-style">Modifying the pagination style</h2>
+<p>If you want to modify particular aspects of the pagination style, you'll want to override one of the pagination classes, and set the attributes that you want to change.</p>
+<pre><code>class LargeResultsSetPagination(PageNumberPagination):
+ page_size = 1000
+ page_size_query_param = 'page_size'
+ max_page_size = 10000
+
+class StandardResultsSetPagination(PageNumberPagination):
+ page_size = 100
+ page_size_query_param = 'page_size'
+ max_page_size = 1000
+</code></pre>
+<p>You can then apply your new style to a view using the <code>.pagination_class</code> attribute:</p>
+<pre><code>class BillingRecordsView(generics.ListAPIView):
+ queryset = Billing.objects.all()
+ serializer = BillingRecordsSerializer
+ pagination_class = LargeResultsSetPagination
+</code></pre>
+<p>Or apply the style globally, using the <code>DEFAULT_PAGINATION_CLASS</code> settings key. For example:</p>
+<pre><code>REST_FRAMEWORK = {
+ 'DEFAULT_PAGINATION_CLASS': 'apps.core.pagination.StandardResultsSetPagination'
+ }
+</code></pre>
+<hr />
+<h1 id="api-reference">API Reference</h1>
+<h2 id="pagenumberpagination">PageNumberPagination</h2>
+<p>This pagination style accepts a single number page number in the request query parameters.</p>
+<p><strong>Request</strong>:</p>
+<pre><code>GET https://api.example.org/accounts/?page=4
</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><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']}
+<p><strong>Response</strong>:</p>
+<pre><code>HTTP 200 OK
+{
+ "count": 1023
+ "next": "https://api.example.org/accounts/?page=5",
+ "previous": "https://api.example.org/accounts/?page=3",
+ "results": [
+ …
+ ]
+}
</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><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
+<h4 id="setup">Setup</h4>
+<p>To enable the <code>PageNumberPagination</code> style globally, use the following configuration, modifying the <code>DEFAULT_PAGE_SIZE</code> as desired:</p>
+<pre><code>REST_FRAMEWORK = {
+ 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
+ 'DEFAULT_PAGE_SIZE': 100
+}
</code></pre>
-<p>We could now use our pagination serializer in a view like this.</p>
-<pre><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)
+<p>On <code>GenericAPIView</code> subclasses you may also set the <code>pagination_class</code> attribute to select <code>PageNumberPagination</code> on a per-view basis.</p>
+<h4 id="configuration">Configuration</h4>
+<p>The <code>PageNumberPagination</code> class includes a number of attributes that may be overridden to modify the pagination style.</p>
+<p>To set these attributes you should override the <code>PageNumberPagination</code> class, and then enable your custom pagination class as above.</p>
+<ul>
+<li><code>page_size</code> - A numeric value indicating the page size. If set, this overrides the <code>DEFAULT_PAGE_SIZE</code> setting. Defaults to the same value as the <code>DEFAULT_PAGE_SIZE</code> settings key.</li>
+<li><code>page_query_param</code> - A string value indicating the name of the query parameter to use for the pagination control.</li>
+<li><code>page_size_query_param</code> - If set, this is a string value indicating the name of a query parameter that allows the client to set the page size on a per-request basis. Defaults to <code>None</code>, indicating that the client may not control the requested page size.</li>
+<li><code>max_page_size</code> - If set, this is a numeric value indicating the maximum allowable requested page size. This attribute is only valid if <code>page_size_query_param</code> is also set.</li>
+<li><code>last_page_strings</code> - A list or tuple of string values indicating values that may be used with the <code>page_query_param</code> to request the final page in the set. Defaults to <code>('last',)</code></li>
+<li><code>template</code> - The name of a template to use when rendering pagination controls in the browsable API. May be overridden to modify the rendering style, or set to <code>None</code> to disable HTML pagination controls completely. Defaults to <code>"rest_framework/pagination/numbers.html"</code>.</li>
+</ul>
+<hr />
+<h2 id="limitoffsetpagination">LimitOffsetPagination</h2>
+<p>This pagination style mirrors the syntax used when looking up multiple database records. The client includes both a "limit" and an
+"offset" query parameter. The limit indicates the maximum number of items to return, and is equivalent to the <code>page_size</code> in other styles. The offset indicates the starting position of the query in relation to the complete set of unpaginated items.</p>
+<p><strong>Request</strong>:</p>
+<pre><code>GET https://api.example.org/accounts/?limit=100&amp;offset=400
</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>
+<p><strong>Response</strong>:</p>
+<pre><code>HTTP 200 OK
+{
+ "count": 1023
+ "next": "https://api.example.org/accounts/?limit=100&amp;offset=500",
+ "previous": "https://api.example.org/accounts/?limit=100&amp;offset=300",
+ "results": [
+ …
+ ]
+}
+</code></pre>
+<h4 id="setup_1">Setup</h4>
+<p>To enable the <code>PageNumberPagination</code> style globally, use the following configuration:</p>
<pre><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`.
+ 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination'
}
</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><code>class PaginatedListView(ListAPIView):
- queryset = ExampleModel.objects.all()
- serializer_class = ExampleModelSerializer
- paginate_by = 10
- paginate_by_param = 'page_size'
- max_paginate_by = 100
+<p>Optionally, you may also set a <code>DEFAULT_PAGE_SIZE</code> key. If the <code>DEFAULT_PAGE_SIZE</code> parameter is also used then the <code>limit</code> query parameter will be optional, and may be omitted by the client.</p>
+<p>On <code>GenericAPIView</code> subclasses you may also set the <code>pagination_class</code> attribute to select <code>LimitOffsetPagination</code> on a per-view basis.</p>
+<h4 id="configuration_1">Configuration</h4>
+<p>The <code>LimitOffsetPagination</code> class includes a number of attributes that may be overridden to modify the pagination style.</p>
+<p>To set these attributes you should override the <code>LimitOffsetPagination</code> class, and then enable your custom pagination class as above.</p>
+<ul>
+<li><code>default_limit</code> - A numeric value indicating the limit to use if one is not provided by the client in a query parameter. Defaults to the same value as the <code>DEFAULT_PAGE_SIZE</code> settings key.</li>
+<li><code>limit_query_param</code> - A string value indicating the name of the "limit" query parameter. Defaults to <code>'limit'</code>.</li>
+<li><code>offset_query_param</code> - A string value indicating the name of the "offset" query parameter. Defaults to <code>'offset'</code>.</li>
+<li><code>max_limit</code> - If set this is a numeric value indicating the maximum allowable limit that may be requested by the client. Defaults to <code>None</code>.</li>
+<li><code>template</code> - The name of a template to use when rendering pagination controls in the browsable API. May be overridden to modify the rendering style, or set to <code>None</code> to disable HTML pagination controls completely. Defaults to <code>"rest_framework/pagination/numbers.html"</code>.</li>
+</ul>
+<hr />
+<h2 id="cursorpagination">CursorPagination</h2>
+<p>The cursor-based pagination presents an opaque "cursor" indicator that the client may use to page through the result set. This pagination style only presents forward and reverse controls, and does not allow the client to navigate to arbitrary positions.</p>
+<p>Cursor based pagination requires that there is a unique, unchanging ordering of items in the result set. This ordering might typically be a creation timestamp on the records, as this presents a consistent ordering to paginate against.</p>
+<p>Cursor based pagination is more complex than other schemes. It also requires that the result set presents a fixed ordering, and does not allow the client to arbitrarily index into the result set. However it does provide the following benefits:</p>
+<ul>
+<li>Provides a consistent pagination view. When used properly <code>CursorPagination</code> ensures that the client will never see the same item twice when paging through records, even when new items are being inserted by other clients during the pagination process.</li>
+<li>Supports usage with very large datasets. With extremely large datasets pagination using offset-based pagination styles may become inefficient or unusable. Cursor based pagination schemes instead have fixed-time properties, and do not slow down as the dataset size increases.</li>
+</ul>
+<h4 id="details-and-limitations">Details and limitations</h4>
+<p>Proper use of cursor based pagination a little attention to detail. You'll need to think about what ordering you want the scheme to be applied against. The default is to order by <code>"-created"</code>. This assumes that <strong>there must be a 'created' timestamp field</strong> on the model instances, and will present a "timeline" style paginated view, with the most recently added items first.</p>
+<p>You can modify the ordering by overriding the <code>'ordering'</code> attribute on the pagination class, or by using the <code>OrderingFilter</code> filter class together with <code>CursorPagination</code>. When used with <code>OrderingFilter</code> you should strongly consider restricting the fields that the user may order by.</p>
+<p>Proper usage of cursor pagination should have an ordering field that satisfies the following:</p>
+<ul>
+<li>Should be an unchanging value, such as a timestamp, slug, or other field that is only set once, on creation.</li>
+<li>Should be unique, or nearly unique. Millisecond precision timestamps are a good example. This implementation of cursor pagination uses a smart "position plus offset" style that allows it to properly support not-strictly-unique values as the ordering.</li>
+<li>Should be a non-nullable value that can be coerced to a string.</li>
+<li>The field should have a database index.</li>
+</ul>
+<p>Using an ordering field that does not satisfy these constraints will generally still work, but you'll be loosing some of the benefits of cursor pagination.</p>
+<p>For more technical details on the implementation we use for cursor pagination, the <a href="http://cramer.io/2011/03/08/building-cursors-for-the-disqus-api/">"Building cursors for the Disqus API"</a> blog post gives a good overview of the basic approach.</p>
+<h4 id="setup_2">Setup</h4>
+<p>To enable the <code>CursorPagination</code> style globally, use the following configuration, modifying the <code>DEFAULT_PAGE_SIZE</code> as desired:</p>
+<pre><code>REST_FRAMEWORK = {
+ 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.CursorPagination',
+ 'DEFAULT_PAGE_SIZE': 100
+}
</code></pre>
-<p>Note that using a <code>paginate_by</code> value of <code>None</code> will turn off pagination for the view.
-Note if you use the <code>PAGINATE_BY_PARAM</code> settings, you also have to set the <code>paginate_by_param</code> attribute in your view to <code>None</code> in order to turn off pagination for those requests that contain the <code>paginate_by_param</code> parameter.</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>
+<p>On <code>GenericAPIView</code> subclasses you may also set the <code>pagination_class</code> attribute to select <code>CursorPagination</code> on a per-view basis.</p>
+<h4 id="configuration_2">Configuration</h4>
+<p>The <code>CursorPagination</code> class includes a number of attributes that may be overridden to modify the pagination style.</p>
+<p>To set these attributes you should override the <code>CursorPagination</code> class, and then enable your custom pagination class as above.</p>
+<ul>
+<li><code>page_size</code> = A numeric value indicating the page size. If set, this overrides the <code>DEFAULT_PAGE_SIZE</code> setting. Defaults to the same value as the <code>DEFAULT_PAGE_SIZE</code> settings key.</li>
+<li><code>cursor_query_param</code> = A string value indicating the name of the "cursor" query parameter. Defaults to <code>'cursor'</code>.</li>
+<li><code>ordering</code> = This should be a string, or list of strings, indicating the field against which the cursor based pagination will be applied. For example: <code>ordering = 'slug'</code>. Defaults to <code>-created</code>. This value may also be overridden by using <code>OrderingFilter</code> on the view.</li>
+<li><code>template</code> = The name of a template to use when rendering pagination controls in the browsable API. May be overridden to modify the rendering style, or set to <code>None</code> to disable HTML pagination controls completely. Defaults to <code>"rest_framework/pagination/previous_and_next.html"</code>.</li>
+</ul>
<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>
+<h1 id="custom-pagination-styles">Custom pagination styles</h1>
+<p>To create a custom pagination serializer class you should subclass <code>pagination.BasePagination</code> and override the <code>paginate_queryset(self, queryset, request, view=None)</code> and <code>get_paginated_response(self, data)</code> methods:</p>
+<ul>
+<li>The <code>paginate_queryset</code> method is passed the initial queryset and should return an iterable object that contains only the data in the requested page.</li>
+<li>The <code>get_paginated_response</code> method is passed the serialized page data and should return a <code>Response</code> instance.</li>
+</ul>
+<p>Note that the <code>paginate_queryset</code> method may set state on the pagination instance, that may later be used by the <code>get_paginated_response</code> method.</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><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.ReadOnlyField(source='paginator.count')
-
- results_field = 'objects'
+<p>Suppose we want to replace the default pagination output style with a modified format that includes the next and previous links under in a nested 'links' key. We could specify a custom pagination class like so:</p>
+<pre><code>class CustomPagination(pagination.PageNumberPagination):
+ def get_paginated_response(self, data):
+ return Response({
+ 'links': {
+ 'next': self.get_next_link(),
+ 'previous': self.get_previous_link()
+ },
+ 'count': self.page.paginator.count,
+ 'results': data
+ })
</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>
+<p>We'd then need to setup the custom class in our configuration:</p>
<pre><code>REST_FRAMEWORK = {
- 'DEFAULT_PAGINATION_SERIALIZER_CLASS':
- 'example_app.pagination.CustomPaginationSerializer',
+ 'DEFAULT_PAGINATION_CLASS': 'my_project.apps.core.pagination.CustomPagination',
+ 'PAGE_SIZE': 100
}
</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><code>class PaginatedListView(generics.ListAPIView):
- model = ExampleModel
- pagination_serializer_class = CustomPaginationSerializer
- paginate_by = 10
+<p>Note that if you care about how the ordering of keys is displayed in responses in the browsable API you might choose to use an <code>OrderedDict</code> when constructing the body of paginated responses, but this is optional.</p>
+<h2 id="header-based-pagination">Header based pagination</h2>
+<p>Let's modify the built-in <code>PageNumberPagination</code> style, so that instead of include the pagination links in the body of the response, we'll instead include a <code>Link</code> header, in a <a href="https://developer.github.com/guides/traversing-with-pagination/">similar style to the GitHub API</a>.</p>
+<pre><code>class LinkHeaderPagination(pagination.PageNumberPagination):
+ def get_paginated_response(self, data):
+ next_url = self.get_next_link()
+ previous_url = self.get_previous_link()
+
+ if next_url is not None and previous_url is not None:
+ link = '&lt;{next_url}; rel="next"&gt;, &lt;{previous_url}; rel="prev"&gt;'
+ elif next_url is not None:
+ link = '&lt;{next_url}; rel="next"&gt;'
+ elif previous_url is not None:
+ link = '&lt;{previous_url}; rel="prev"&gt;'
+ else:
+ link = ''
+
+ link = link.format(next_url=next_url, previous_url=previous_url)
+ headers = {'Link': link} if link else {}
+
+ return Response(data, headers=headers)
</code></pre>
+<h2 id="using-your-custom-pagination-class">Using your custom pagination class</h2>
+<p>To have your custom pagination class be used by default, use the <code>DEFAULT_PAGINATION_CLASS</code> setting:</p>
+<pre><code>REST_FRAMEWORK = {
+ 'DEFAULT_PAGINATION_CLASS': 'my_project.apps.core.pagination.LinkHeaderPagination',
+ 'PAGE_SIZE': 100
+}
+</code></pre>
+<p>API responses for list endpoints will now include a <code>Link</code> header, instead of including the pagination links as part of the body of the response, for example:</p>
+<hr />
+<p><img alt="Link Header" src="../../../img/link-header-pagination.png" /></p>
+<p><em>A custom pagination style, using the 'Link' header'</em></p>
+<hr />
+<h1 id="html-pagination-controls">HTML pagination controls</h1>
+<p>By default using the pagination classes will cause HTML pagination controls to be displayed in the browsable API. There are two built-in display styles. The <code>PageNumberPagination</code> and <code>LimitOffsetPagination</code> classes display a list of page numbers with previous and next controls. The <code>CursorPagination</code> class displays a simpler style that only displays a previous and next control.</p>
+<h2 id="customizing-the-controls">Customizing the controls</h2>
+<p>You can override the templates that render the HTML pagination controls. The two built-in styles are:</p>
+<ul>
+<li><code>rest_framework/pagination/numbers.html</code></li>
+<li><code>rest_framework/pagination/previous_and_next.html</code></li>
+</ul>
+<p>Providing a template with either of these paths in a global template directory will override the default rendering for the relevant pagination classes.</p>
+<p>Alternatively you can disable HTML pagination controls completely by subclassing on of the existing classes, setting <code>template = None</code> as an attribute on the class. You'll then need to configure your <code>DEFAULT_PAGINATION_CLASS</code> settings key to use your custom class as the default pagination style.</p>
+<h4 id="low-level-api">Low-level API</h4>
+<p>The low-level API for determining if a pagination class should display the controls or not is exposed as a <code>display_page_controls</code> attribute on the pagination instance. Custom pagination classes should be set to <code>True</code> in the <code>paginate_queryset</code> method if they require the HTML pagination controls to be displayed.</p>
+<p>The <code>.to_html()</code> and <code>.get_html_context()</code> methods may also be overridden in a custom pagination class in order to further customize how the controls are rendered.</p>
+<hr />
<h1 id="third-party-packages">Third party packages</h1>
<p>The following third party packages are also available.</p>
<h2 id="drf-extensions">DRF-extensions</h2>
diff --git a/api-guide/parsers/index.html b/api-guide/parsers/index.html
index e04f563e..132d146d 100644
--- a/api-guide/parsers/index.html
+++ b/api-guide/parsers/index.html
@@ -189,6 +189,10 @@
</li>
<li >
+ <a href="../versioning">Versioning</a>
+ </li>
+
+ <li >
<a href="../content-negotiation">Content negotiation</a>
</li>
@@ -232,6 +236,10 @@
</li>
<li >
+ <a href="../../topics/internationalization">Internationalization</a>
+ </li>
+
+ <li >
<a href="../../topics/ajax-csrf-cors">AJAX, CSRF & CORS</a>
</li>
@@ -260,23 +268,11 @@
</li>
<li >
- <a href="../../topics/rest-framework-2-announcement">2.0 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.2-announcement">2.2 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.3-announcement">2.3 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.4-announcement">2.4 Announcement</a>
+ <a href="../../topics/3.0-announcement">3.0 Announcement</a>
</li>
<li >
- <a href="../../topics/3.0-announcement">3.0 Announcement</a>
+ <a href="../../topics/3.1-announcement">3.1 Announcement</a>
</li>
<li >
@@ -287,10 +283,6 @@
<a href="../../topics/release-notes">Release Notes</a>
</li>
- <li >
- <a href="../../topics/credits">Credits</a>
- </li>
-
</ul>
</li>
@@ -378,14 +370,6 @@
</li>
<li>
- <a href="#yamlparser">YAMLParser</a>
- </li>
-
- <li>
- <a href="#xmlparser">XMLParser</a>
- </li>
-
- <li>
<a href="#formparser">FormParser</a>
</li>
@@ -430,6 +414,14 @@
<li>
+ <a href="#yaml">YAML</a>
+ </li>
+
+ <li>
+ <a href="#xml">XML</a>
+ </li>
+
+ <li>
<a href="#messagepack">MessagePack</a>
</li>
@@ -472,34 +464,34 @@ sending more complex data than simple forms</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>
+<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 only requests with <code>JSON</code> content, instead of the default of JSON or form data.</p>
<pre><code>REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES': (
- 'rest_framework.parsers.YAMLParser',
+ 'rest_framework.parsers.JSONParser',
)
}
</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><code>from rest_framework.parsers import YAMLParser
+<pre><code>from rest_framework.parsers import JSONParser
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.
+ A view that can accept POST requests with JSON content.
"""
- parser_classes = (YAMLParser,)
+ parser_classes = (JSONParser,)
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><code>@api_view(['POST'])
-@parser_classes((YAMLParser,))
+@parser_classes((JSONParser,))
def example_view(request, format=None):
"""
- A view that can accept POST requests with YAML content.
+ A view that can accept POST requests with JSON content.
"""
return Response({'received data': request.data})
</code></pre>
@@ -508,16 +500,6 @@ def example_view(request, format=None):
<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.</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>
@@ -561,7 +543,7 @@ def example_view(request, format=None):
<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>
+<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><code>class PlainTextParser(BaseParser):
"""
Plain text parser.
@@ -578,6 +560,38 @@ def parse(self, stream, media_type=None, parser_context=None):
<hr />
<h1 id="third-party-packages">Third party packages</h1>
<p>The following third party packages are also available.</p>
+<h2 id="yaml">YAML</h2>
+<p><a href="http://jpadilla.github.io/django-rest-framework-yaml/">REST framework YAML</a> provides <a href="http://www.yaml.org/">YAML</a> parsing and rendering support. It was previously included directly in the REST framework package, and is now instead supported as a third-party package.</p>
+<h4 id="installation-configuration">Installation &amp; configuration</h4>
+<p>Install using pip.</p>
+<pre><code>$ pip install djangorestframework-yaml
+</code></pre>
+<p>Modify your REST framework settings.</p>
+<pre><code>REST_FRAMEWORK = {
+ 'DEFAULT_PARSER_CLASSES': (
+ 'rest_framework_yaml.parsers.YAMLParser',
+ ),
+ 'DEFAULT_RENDERER_CLASSES': (
+ 'rest_framework_yaml.renderers.YAMLRenderer',
+ ),
+}
+</code></pre>
+<h2 id="xml">XML</h2>
+<p><a href="http://jpadilla.github.io/django-rest-framework-xml/">REST Framework XML</a> provides a simple informal XML format. It was previously included directly in the REST framework package, and is now instead supported as a third-party package.</p>
+<h4 id="installation-configuration_1">Installation &amp; configuration</h4>
+<p>Install using pip.</p>
+<pre><code>$ pip install djangorestframework-xml
+</code></pre>
+<p>Modify your REST framework settings.</p>
+<pre><code>REST_FRAMEWORK = {
+ 'DEFAULT_PARSER_CLASSES': (
+ 'rest_framework_xml.parsers.XMLParser',
+ ),
+ 'DEFAULT_RENDERER_CLASSES': (
+ 'rest_framework_xml.renderers.XMLRenderer',
+ ),
+}
+</code></pre>
<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>
<h2 id="camelcase-json">CamelCase JSON</h2>
diff --git a/api-guide/permissions/index.html b/api-guide/permissions/index.html
index 7b6f889c..5e921802 100644
--- a/api-guide/permissions/index.html
+++ b/api-guide/permissions/index.html
@@ -189,6 +189,10 @@
</li>
<li >
+ <a href="../versioning">Versioning</a>
+ </li>
+
+ <li >
<a href="../content-negotiation">Content negotiation</a>
</li>
@@ -232,6 +236,10 @@
</li>
<li >
+ <a href="../../topics/internationalization">Internationalization</a>
+ </li>
+
+ <li >
<a href="../../topics/ajax-csrf-cors">AJAX, CSRF & CORS</a>
</li>
@@ -260,23 +268,11 @@
</li>
<li >
- <a href="../../topics/rest-framework-2-announcement">2.0 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.2-announcement">2.2 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.3-announcement">2.3 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.4-announcement">2.4 Announcement</a>
+ <a href="../../topics/3.0-announcement">3.0 Announcement</a>
</li>
<li >
- <a href="../../topics/3.0-announcement">3.0 Announcement</a>
+ <a href="../../topics/3.1-announcement">3.1 Announcement</a>
</li>
<li >
@@ -287,10 +283,6 @@
<a href="../../topics/release-notes">Release Notes</a>
</li>
- <li >
- <a href="../../topics/credits">Credits</a>
- </li>
-
</ul>
</li>
@@ -405,10 +397,6 @@
<a href="#djangoobjectpermissions">DjangoObjectPermissions</a>
</li>
- <li>
- <a href="#tokenhasreadwritescope">TokenHasReadWriteScope</a>
- </li>
-
@@ -575,16 +563,6 @@ def example_view(request, format=None):
<hr />
<p><strong>Note</strong>: If you need object level <code>view</code> permissions for <code>GET</code>, <code>HEAD</code> and <code>OPTIONS</code> requests, you'll want to consider also 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>
<hr />
-<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>
diff --git a/api-guide/relations/index.html b/api-guide/relations/index.html
index ee51a7e3..67ecbb4f 100644
--- a/api-guide/relations/index.html
+++ b/api-guide/relations/index.html
@@ -189,6 +189,10 @@
</li>
<li >
+ <a href="../versioning">Versioning</a>
+ </li>
+
+ <li >
<a href="../content-negotiation">Content negotiation</a>
</li>
@@ -232,6 +236,10 @@
</li>
<li >
+ <a href="../../topics/internationalization">Internationalization</a>
+ </li>
+
+ <li >
<a href="../../topics/ajax-csrf-cors">AJAX, CSRF & CORS</a>
</li>
@@ -260,23 +268,11 @@
</li>
<li >
- <a href="../../topics/rest-framework-2-announcement">2.0 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.2-announcement">2.2 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.3-announcement">2.3 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.4-announcement">2.4 Announcement</a>
+ <a href="../../topics/3.0-announcement">3.0 Announcement</a>
</li>
<li >
- <a href="../../topics/3.0-announcement">3.0 Announcement</a>
+ <a href="../../topics/3.1-announcement">3.1 Announcement</a>
</li>
<li >
@@ -287,10 +283,6 @@
<a href="../../topics/release-notes">Release Notes</a>
</li>
- <li >
- <a href="../../topics/credits">Credits</a>
- </li>
-
</ul>
</li>
diff --git a/api-guide/renderers/index.html b/api-guide/renderers/index.html
index 58d6a3cc..694544fb 100644
--- a/api-guide/renderers/index.html
+++ b/api-guide/renderers/index.html
@@ -189,6 +189,10 @@
</li>
<li >
+ <a href="../versioning">Versioning</a>
+ </li>
+
+ <li >
<a href="../content-negotiation">Content negotiation</a>
</li>
@@ -232,6 +236,10 @@
</li>
<li >
+ <a href="../../topics/internationalization">Internationalization</a>
+ </li>
+
+ <li >
<a href="../../topics/ajax-csrf-cors">AJAX, CSRF & CORS</a>
</li>
@@ -260,23 +268,11 @@
</li>
<li >
- <a href="../../topics/rest-framework-2-announcement">2.0 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.2-announcement">2.2 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.3-announcement">2.3 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.4-announcement">2.4 Announcement</a>
+ <a href="../../topics/3.0-announcement">3.0 Announcement</a>
</li>
<li >
- <a href="../../topics/3.0-announcement">3.0 Announcement</a>
+ <a href="../../topics/3.1-announcement">3.1 Announcement</a>
</li>
<li >
@@ -287,10 +283,6 @@
<a href="../../topics/release-notes">Release Notes</a>
</li>
- <li >
- <a href="../../topics/credits">Credits</a>
- </li>
-
</ul>
</li>
@@ -382,22 +374,6 @@
</li>
<li>
- <a href="#jsonprenderer">JSONPRenderer</a>
- </li>
-
- <li>
- <a href="#yamlrenderer">YAMLRenderer</a>
- </li>
-
- <li>
- <a href="#unicodeyamlrenderer">UnicodeYAMLRenderer</a>
- </li>
-
- <li>
- <a href="#xmlrenderer">XMLRenderer</a>
- </li>
-
- <li>
<a href="#templatehtmlrenderer">TemplateHTMLRenderer</a>
</li>
@@ -478,6 +454,18 @@
<li>
+ <a href="#yaml">YAML</a>
+ </li>
+
+ <li>
+ <a href="#xml">XML</a>
+ </li>
+
+ <li>
+ <a href="#jsonp">JSONP</a>
+ </li>
+
+ <li>
<a href="#messagepack">MessagePack</a>
</li>
@@ -527,10 +515,10 @@
<p>The basic process of content negotiation involves examining the request's <code>Accept</code> header, to determine which media types it expects in the response. Optionally, format suffixes on the URL may be used to explicitly request a particular representation. For example the URL <code>http://example.com/api/users_count.json</code> might be an endpoint that always returns JSON data.</p>
<p>For more information see the documentation on <a href="../content-negotiation">content 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>
+<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>JSON</code> as the main media type and also include the self describing API.</p>
<pre><code>REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': (
- 'rest_framework.renderers.YAMLRenderer',
+ 'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
)
}
@@ -538,15 +526,15 @@
<p>You can also set the renderers used for an individual view, or viewset,
using the <code>APIView</code> class based views.</p>
<pre><code>from django.contrib.auth.models import User
-from rest_framework.renderers import JSONRenderer, YAMLRenderer
+from rest_framework.renderers import JSONRenderer
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.
+ A view that returns the count of active users in JSON.
"""
- renderer_classes = (JSONRenderer, YAMLRenderer)
+ renderer_classes = (JSONRenderer, )
def get(self, request, format=None):
user_count = User.objects.filter(active=True).count()
@@ -555,10 +543,10 @@ class UserCountView(APIView):
</code></pre>
<p>Or, if you're using the <code>@api_view</code> decorator with function based views.</p>
<pre><code>@api_view(['GET'])
-@renderer_classes((JSONRenderer, JSONPRenderer))
+@renderer_classes((JSONRenderer,))
def user_count_view(request, format=None):
"""
- A view that returns the count of active users, in JSON or JSONp.
+ A view that returns the count of active users in JSON.
"""
user_count = User.objects.filter(active=True).count()
content = {'user_count': user_count}
@@ -585,41 +573,6 @@ def user_count_view(request, format=None):
<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>
-<hr />
-<p><strong>Warning</strong>: If you require cross-domain AJAX requests, you should almost certainly be 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">CORS documentation</a> for more details.</p>
-<p>The <code>jsonp</code> approach is essentially a browser hack, and is <a href="http://stackoverflow.com/questions/613962/is-jsonp-safe-to-use">only appropriate for globally readable API endpoints</a>, where <code>GET</code> requests are unauthenticated and do not require any user permissions.</p>
-<hr />
-<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>Note that non-ascii characters will be rendered using <code>\uXXXX</code> character escape. For example:</p>
-<pre><code>unicode black star: "\u2605"
-</code></pre>
-<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="unicodeyamlrenderer">UnicodeYAMLRenderer</h2>
-<p>Renders the request data into <code>YAML</code>.</p>
-<p>Requires the <code>pyyaml</code> package to be installed.</p>
-<p>Note that non-ascii characters will not be character escaped. For example:</p>
-<pre><code>unicode black star: ★
-</code></pre>
-<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>
@@ -791,10 +744,59 @@ In this case you can underspecify the media types it should respond to, by using
<hr />
<h1 id="third-party-packages">Third party packages</h1>
<p>The following third party packages are also available.</p>
+<h2 id="yaml">YAML</h2>
+<p><a href="http://jpadilla.github.io/django-rest-framework-yaml/">REST framework YAML</a> provides <a href="http://www.yaml.org/">YAML</a> parsing and rendering support. It was previously included directly in the REST framework package, and is now instead supported as a third-party package.</p>
+<h4 id="installation-configuration">Installation &amp; configuration</h4>
+<p>Install using pip.</p>
+<pre><code>$ pip install djangorestframework-yaml
+</code></pre>
+<p>Modify your REST framework settings.</p>
+<pre><code>REST_FRAMEWORK = {
+ 'DEFAULT_PARSER_CLASSES': (
+ 'rest_framework_yaml.parsers.YAMLParser',
+ ),
+ 'DEFAULT_RENDERER_CLASSES': (
+ 'rest_framework_yaml.renderers.YAMLRenderer',
+ ),
+}
+</code></pre>
+<h2 id="xml">XML</h2>
+<p><a href="http://jpadilla.github.io/django-rest-framework-xml/">REST Framework XML</a> provides a simple informal XML format. It was previously included directly in the REST framework package, and is now instead supported as a third-party package.</p>
+<h4 id="installation-configuration_1">Installation &amp; configuration</h4>
+<p>Install using pip.</p>
+<pre><code>$ pip install djangorestframework-xml
+</code></pre>
+<p>Modify your REST framework settings.</p>
+<pre><code>REST_FRAMEWORK = {
+ 'DEFAULT_PARSER_CLASSES': (
+ 'rest_framework_xml.parsers.XMLParser',
+ ),
+ 'DEFAULT_RENDERER_CLASSES': (
+ 'rest_framework_xml.renderers.XMLRenderer',
+ ),
+}
+</code></pre>
+<h2 id="jsonp">JSONP</h2>
+<p><a href="http://jpadilla.github.io/django-rest-framework-jsonp/">REST framework JSONP</a> provides JSONP rendering support. It was previously included directly in the REST framework package, and is now instead supported as a third-party package.</p>
+<hr />
+<p><strong>Warning</strong>: If you require cross-domain AJAX requests, you should generally be 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="http://www.django-rest-framework.org/topics/ajax-csrf-cors/">CORS documentation</a> for more details.</p>
+<p>The <code>jsonp</code> approach is essentially a browser hack, and is <a href="http://stackoverflow.com/questions/613962/is-jsonp-safe-to-use">only appropriate for globally readable API endpoints</a>, where <code>GET</code> requests are unauthenticated and do not require any user permissions.</p>
+<hr />
+<h4 id="installation-configuration_2">Installation &amp; configuration</h4>
+<p>Install using pip.</p>
+<pre><code>$ pip install djangorestframework-jsonp
+</code></pre>
+<p>Modify your REST framework settings.</p>
+<pre><code>REST_FRAMEWORK = {
+ 'DEFAULT_RENDERER_CLASSES': (
+ 'rest_framework_yaml.renderers.JSONPRenderer',
+ ),
+}
+</code></pre>
<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>
+<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>
<h2 id="camelcase-json">CamelCase JSON</h2>
diff --git a/api-guide/requests/index.html b/api-guide/requests/index.html
index 4cc5fd3d..3db6d380 100644
--- a/api-guide/requests/index.html
+++ b/api-guide/requests/index.html
@@ -189,6 +189,10 @@
</li>
<li >
+ <a href="../versioning">Versioning</a>
+ </li>
+
+ <li >
<a href="../content-negotiation">Content negotiation</a>
</li>
@@ -232,6 +236,10 @@
</li>
<li >
+ <a href="../../topics/internationalization">Internationalization</a>
+ </li>
+
+ <li >
<a href="../../topics/ajax-csrf-cors">AJAX, CSRF & CORS</a>
</li>
@@ -260,23 +268,11 @@
</li>
<li >
- <a href="../../topics/rest-framework-2-announcement">2.0 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.2-announcement">2.2 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.3-announcement">2.3 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.4-announcement">2.4 Announcement</a>
+ <a href="../../topics/3.0-announcement">3.0 Announcement</a>
</li>
<li >
- <a href="../../topics/3.0-announcement">3.0 Announcement</a>
+ <a href="../../topics/3.1-announcement">3.1 Announcement</a>
</li>
<li >
@@ -287,10 +283,6 @@
<a href="../../topics/release-notes">Release Notes</a>
</li>
- <li >
- <a href="../../topics/credits">Credits</a>
- </li>
-
</ul>
</li>
@@ -492,7 +484,7 @@
<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 Django's standard <code>request.GET</code>. Doing so will help keep your codebase more correct and obvious - any HTTP method type may include query parameters, not just <code>GET</code> requests.</p>
<h2 id="data-and-files">.DATA and .FILES</h2>
-<p>The old-style version 2.x <code>request.data</code> and <code>request.FILES</code> attributes are still available, but are now pending deprecation in favor of the unified <code>request.data</code> attribute.</p>
+<p>The old-style version 2.x <code>request.DATA</code> and <code>request.FILES</code> attributes are still available, but are now pending deprecation in favor of the unified <code>request.data</code> attribute.</p>
<h2 id="query_params_1">.QUERY_PARAMS</h2>
<p>The old-style version 2.x <code>request.QUERY_PARAMS</code> attribute is still available, but is now pending deprecation in favor of the more pythonic <code>request.query_params</code>.</p>
<h2 id="parsers">.parsers</h2>
diff --git a/api-guide/responses/index.html b/api-guide/responses/index.html
index 43b75ade..4588b623 100644
--- a/api-guide/responses/index.html
+++ b/api-guide/responses/index.html
@@ -189,6 +189,10 @@
</li>
<li >
+ <a href="../versioning">Versioning</a>
+ </li>
+
+ <li >
<a href="../content-negotiation">Content negotiation</a>
</li>
@@ -232,6 +236,10 @@
</li>
<li >
+ <a href="../../topics/internationalization">Internationalization</a>
+ </li>
+
+ <li >
<a href="../../topics/ajax-csrf-cors">AJAX, CSRF & CORS</a>
</li>
@@ -260,23 +268,11 @@
</li>
<li >
- <a href="../../topics/rest-framework-2-announcement">2.0 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.2-announcement">2.2 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.3-announcement">2.3 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.4-announcement">2.4 Announcement</a>
+ <a href="../../topics/3.0-announcement">3.0 Announcement</a>
</li>
<li >
- <a href="../../topics/3.0-announcement">3.0 Announcement</a>
+ <a href="../../topics/3.1-announcement">3.1 Announcement</a>
</li>
<li >
@@ -287,10 +283,6 @@
<a href="../../topics/release-notes">Release Notes</a>
</li>
- <li >
- <a href="../../topics/credits">Credits</a>
- </li>
-
</ul>
</li>
diff --git a/api-guide/reverse/index.html b/api-guide/reverse/index.html
index b716060d..c0d42c32 100644
--- a/api-guide/reverse/index.html
+++ b/api-guide/reverse/index.html
@@ -189,6 +189,10 @@
</li>
<li >
+ <a href="../versioning">Versioning</a>
+ </li>
+
+ <li >
<a href="../content-negotiation">Content negotiation</a>
</li>
@@ -232,6 +236,10 @@
</li>
<li >
+ <a href="../../topics/internationalization">Internationalization</a>
+ </li>
+
+ <li >
<a href="../../topics/ajax-csrf-cors">AJAX, CSRF & CORS</a>
</li>
@@ -260,23 +268,11 @@
</li>
<li >
- <a href="../../topics/rest-framework-2-announcement">2.0 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.2-announcement">2.2 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.3-announcement">2.3 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.4-announcement">2.4 Announcement</a>
+ <a href="../../topics/3.0-announcement">3.0 Announcement</a>
</li>
<li >
- <a href="../../topics/3.0-announcement">3.0 Announcement</a>
+ <a href="../../topics/3.1-announcement">3.1 Announcement</a>
</li>
<li >
@@ -287,10 +283,6 @@
<a href="../../topics/release-notes">Release Notes</a>
</li>
- <li >
- <a href="../../topics/credits">Credits</a>
- </li>
-
</ul>
</li>
diff --git a/api-guide/routers/index.html b/api-guide/routers/index.html
index 80bf512d..33a225fc 100644
--- a/api-guide/routers/index.html
+++ b/api-guide/routers/index.html
@@ -189,6 +189,10 @@
</li>
<li >
+ <a href="../versioning">Versioning</a>
+ </li>
+
+ <li >
<a href="../content-negotiation">Content negotiation</a>
</li>
@@ -232,6 +236,10 @@
</li>
<li >
+ <a href="../../topics/internationalization">Internationalization</a>
+ </li>
+
+ <li >
<a href="../../topics/ajax-csrf-cors">AJAX, CSRF & CORS</a>
</li>
@@ -260,23 +268,11 @@
</li>
<li >
- <a href="../../topics/rest-framework-2-announcement">2.0 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.2-announcement">2.2 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.3-announcement">2.3 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.4-announcement">2.4 Announcement</a>
+ <a href="../../topics/3.0-announcement">3.0 Announcement</a>
</li>
<li >
- <a href="../../topics/3.0-announcement">3.0 Announcement</a>
+ <a href="../../topics/3.1-announcement">3.1 Announcement</a>
</li>
<li >
@@ -287,10 +283,6 @@
<a href="../../topics/release-notes">Release Notes</a>
</li>
- <li >
- <a href="../../topics/credits">Credits</a>
- </li>
-
</ul>
</li>
diff --git a/api-guide/serializers/index.html b/api-guide/serializers/index.html
index 4bb06d3b..b5b73213 100644
--- a/api-guide/serializers/index.html
+++ b/api-guide/serializers/index.html
@@ -189,6 +189,10 @@
</li>
<li >
+ <a href="../versioning">Versioning</a>
+ </li>
+
+ <li >
<a href="../content-negotiation">Content negotiation</a>
</li>
@@ -232,6 +236,10 @@
</li>
<li >
+ <a href="../../topics/internationalization">Internationalization</a>
+ </li>
+
+ <li >
<a href="../../topics/ajax-csrf-cors">AJAX, CSRF & CORS</a>
</li>
@@ -260,23 +268,11 @@
</li>
<li >
- <a href="../../topics/rest-framework-2-announcement">2.0 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.2-announcement">2.2 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.3-announcement">2.3 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.4-announcement">2.4 Announcement</a>
+ <a href="../../topics/3.0-announcement">3.0 Announcement</a>
</li>
<li >
- <a href="../../topics/3.0-announcement">3.0 Announcement</a>
+ <a href="../../topics/3.1-announcement">3.1 Announcement</a>
</li>
<li >
@@ -287,10 +283,6 @@
<a href="../../topics/release-notes">Release Notes</a>
</li>
- <li >
- <a href="../../topics/credits">Credits</a>
- </li>
-
</ul>
</li>
@@ -414,7 +406,7 @@
</li>
<li>
- <a href="#specifying-which-fields-should-be-included">Specifying which fields should be included</a>
+ <a href="#specifying-which-fields-to-include">Specifying which fields to include</a>
</li>
<li>
@@ -426,11 +418,11 @@
</li>
<li>
- <a href="#specifying-which-fields-should-be-read-only">Specifying which fields should be read-only</a>
+ <a href="#specifying-read-only-fields">Specifying read only fields</a>
</li>
<li>
- <a href="#specifying-additional-keyword-arguments-for-fields">Specifying additional keyword arguments for fields.</a>
+ <a href="#additional-keyword-arguments">Additional keyword arguments</a>
</li>
<li>
@@ -441,6 +433,10 @@
<a href="#inheritance-of-the-meta-class">Inheritance of the 'Meta' class</a>
</li>
+ <li>
+ <a href="#customizing-field-mappings">Customizing field mappings</a>
+ </li>
+
@@ -920,7 +916,7 @@ AccountSerializer():
name = CharField(allow_blank=True, max_length=100, required=False)
owner = PrimaryKeyRelatedField(queryset=User.objects.all())
</code></pre>
-<h2 id="specifying-which-fields-should-be-included">Specifying which fields should be included</h2>
+<h2 id="specifying-which-fields-to-include">Specifying which fields to include</h2>
<p>If you only want a subset of the default fields to be used in a model serializer, you can do so using <code>fields</code> or <code>exclude</code> options, just as you would with a <code>ModelForm</code>.</p>
<p>For example:</p>
<pre><code>class AccountSerializer(serializers.ModelSerializer):
@@ -950,7 +946,7 @@ AccountSerializer():
model = Account
</code></pre>
<p>Extra fields can correspond to any property or callable on the model.</p>
-<h2 id="specifying-which-fields-should-be-read-only">Specifying which fields should be read-only</h2>
+<h2 id="specifying-read-only-fields">Specifying read only fields</h2>
<p>You may wish to specify multiple fields as read-only. Instead of adding each field explicitly with the <code>read_only=True</code> attribute, you may use the shortcut Meta option, <code>read_only_fields</code>.</p>
<p>This option should be a list or tuple of field names, and is declared as follows:</p>
<pre><code>class AccountSerializer(serializers.ModelSerializer):
@@ -968,7 +964,7 @@ AccountSerializer():
</code></pre>
<p>Please review the <a href="../..//api-guide/validators/">Validators Documentation</a> for details on the <a href="../..//api-guide/validators/#uniquetogethervalidator">UniqueTogetherValidator</a> and <a href="../..//api-guide/validators/#currentuserdefault">CurrentUserDefault</a> classes.</p>
<hr />
-<h2 id="specifying-additional-keyword-arguments-for-fields">Specifying additional keyword arguments for fields.</h2>
+<h2 id="additional-keyword-arguments">Additional keyword arguments</h2>
<p>There is also a shortcut allowing you to specify arbitrary additional keyword arguments on fields, using the <code>extra_kwargs</code> option. Similarly to <code>read_only_fields</code> this means you do not need to explicitly declare the field on the serializer.</p>
<p>This option is a dictionary, mapping field names to a dictionary of keyword arguments. For example:</p>
<pre><code>class CreateUserSerializer(serializers.ModelSerializer):
@@ -997,6 +993,43 @@ AccountSerializer():
model = Account
</code></pre>
<p>Typically we would recommend <em>not</em> using inheritance on inner Meta classes, but instead declaring all options explicitly.</p>
+<h2 id="customizing-field-mappings">Customizing field mappings</h2>
+<p>The ModelSerializer class also exposes an API that you can override in order to alter how serializer fields are automatically determined when instantiating the serializer.</p>
+<p>Normally if a <code>ModelSerializer</code> does not generate the fields you need by default the you should either add them to the class explicitly, or simply use a regular <code>Serializer</code> class instead. However in some cases you may want to create a new base class that defines how the serializer fields are created for any given model.</p>
+<h3 id="serializer_field_mapping"><code>.serializer_field_mapping</code></h3>
+<p>A mapping of Django model classes to REST framework serializer classes. You can override this mapping to alter the default serializer classes that should be used for each model class.</p>
+<h3 id="serializer_related_field"><code>.serializer_related_field</code></h3>
+<p>This property should be the serializer field class, that is used for relational fields by default.</p>
+<p>For <code>ModelSerializer</code> this defaults to <code>PrimaryKeyRelatedField</code>.</p>
+<p>For <code>HyperlinkedModelSerializer</code> this defaults to <code>serializers.HyperlinkedRelatedField</code>.</p>
+<h3 id="serializer_url_field"><code>serializer_url_field</code></h3>
+<p>The serializer field class that should be used for any <code>url</code> field on the serializer.</p>
+<p>Defaults to <code>serializers.HyperlinkedIdentityField</code></p>
+<h3 id="serializer_choice_field"><code>serializer_choice_field</code></h3>
+<p>The serializer field class that should be used for any choice fields on the serializer.</p>
+<p>Defaults to <code>serializers.ChoiceField</code></p>
+<h3 id="the-field_class-and-field_kwargs-api">The field_class and field_kwargs API</h3>
+<p>The following methods are called to determine the class and keyword arguments for each field that should be automatically included on the serializer. Each of these methods should return a two tuple of <code>(field_class, field_kwargs)</code>.</p>
+<h3 id="build_standard_fieldself-field_name-model_field"><code>.build_standard_field(self, field_name, model_field)</code></h3>
+<p>Called to generate a serializer field that maps to a standard model field.</p>
+<p>The default implementation returns a serializer class based on the <code>serializer_field_mapping</code> attribute.</p>
+<h3 id="build_relational_fieldself-field_name-relation_info"><code>.build_relational_field(self, field_name, relation_info)</code></h3>
+<p>Called to generate a serializer field that maps to a relational model field.</p>
+<p>The default implementation returns a serializer class based on the <code>serializer_relational_field</code> attribute.</p>
+<p>The <code>relation_info</code> argument is a named tuple, that contains <code>model_field</code>, <code>related_model</code>, <code>to_many</code> and <code>has_through_model</code> properties.</p>
+<h3 id="build_nested_fieldself-field_name-relation_info-nested_depth"><code>.build_nested_field(self, field_name, relation_info, nested_depth)</code></h3>
+<p>Called to generate a serializer field that maps to a relational model field, when the <code>depth</code> option has been set.</p>
+<p>The default implementation dynamically creates a nested serializer class based on either <code>ModelSerializer</code> or <code>HyperlinkedModelSerializer</code>.</p>
+<p>The <code>nested_depth</code> will be the value of the <code>depth</code> option, minus one.</p>
+<p>The <code>relation_info</code> argument is a named tuple, that contains <code>model_field</code>, <code>related_model</code>, <code>to_many</code> and <code>has_through_model</code> properties.</p>
+<h3 id="build_property_fieldself-field_name-model_class"><code>.build_property_field(self, field_name, model_class)</code></h3>
+<p>Called to generate a serializer field that maps to a property or zero-argument method on the model class.</p>
+<p>The default implementation returns a <code>ReadOnlyField</code> class.</p>
+<h3 id="build_url_fieldself-field_name-model_class"><code>.build_url_field(self, field_name, model_class)</code></h3>
+<p>Called to generate a serializer field for the serializer's own <code>url</code> field. The default implementation returns a <code>HyperlinkedIdentityField</code> class.</p>
+<h3 id="build_unknown_fieldself-field_name-model_class"><code>.build_unknown_field(self, field_name, model_class)</code></h3>
+<p>Called when the field name did not map to any model field or model property.
+The default implementation raises an error, although subclasses may customize this behavior.</p>
<hr />
<h1 id="hyperlinkedmodelserializer">HyperlinkedModelSerializer</h1>
<p>The <code>HyperlinkedModelSerializer</code> class is similar to the <code>ModelSerializer</code> class except that it uses hyperlinks to represent relationships, rather than primary keys.</p>
diff --git a/api-guide/settings/index.html b/api-guide/settings/index.html
index f3062be6..ac100eb4 100644
--- a/api-guide/settings/index.html
+++ b/api-guide/settings/index.html
@@ -189,6 +189,10 @@
</li>
<li >
+ <a href="../versioning">Versioning</a>
+ </li>
+
+ <li >
<a href="../content-negotiation">Content negotiation</a>
</li>
@@ -232,6 +236,10 @@
</li>
<li >
+ <a href="../../topics/internationalization">Internationalization</a>
+ </li>
+
+ <li >
<a href="../../topics/ajax-csrf-cors">AJAX, CSRF & CORS</a>
</li>
@@ -260,23 +268,11 @@
</li>
<li >
- <a href="../../topics/rest-framework-2-announcement">2.0 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.2-announcement">2.2 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.3-announcement">2.3 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.4-announcement">2.4 Announcement</a>
+ <a href="../../topics/3.0-announcement">3.0 Announcement</a>
</li>
<li >
- <a href="../../topics/3.0-announcement">3.0 Announcement</a>
+ <a href="../../topics/3.1-announcement">3.1 Announcement</a>
</li>
<li >
@@ -287,10 +283,6 @@
<a href="../../topics/release-notes">Release Notes</a>
</li>
- <li >
- <a href="../../topics/credits">Credits</a>
- </li>
-
</ul>
</li>
@@ -378,6 +370,10 @@
</li>
<li>
+ <a href="#versioning-settings">Versioning settings</a>
+ </li>
+
+ <li>
<a href="#authentication-settings">Authentication settings</a>
</li>
@@ -433,10 +429,10 @@
<p>For example your project's <code>settings.py</code> file might include something like this:</p>
<pre><code>REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': (
- 'rest_framework.renderers.YAMLRenderer',
+ 'rest_framework.renderers.JSONRenderer',
),
'DEFAULT_PARSER_CLASSES': (
- 'rest_framework.parsers.YAMLParser',
+ 'rest_framework.parsers.JSONParser',
)
}
</code></pre>
@@ -534,6 +530,17 @@ If set to <code>None</code> then generic filtering is disabled.</p>
<p>The name of a query parameter, which can be used to specify the ordering of results returned by <code>OrderingFilter</code>.</p>
<p>Default: <code>ordering</code></p>
<hr />
+<h2 id="versioning-settings">Versioning settings</h2>
+<h4 id="default_version">DEFAULT_VERSION</h4>
+<p>The value that should be used for <code>request.version</code> when no versioning information is present.</p>
+<p>Default: <code>None</code></p>
+<h4 id="allowed_versions">ALLOWED_VERSIONS</h4>
+<p>If set, this value will restrict the set of versions that may be returned by the versioning scheme, and will raise an error if the provided version if not in this set.</p>
+<p>Default: <code>None</code></p>
+<h4 id="version_parameter">VERSION_PARAMETER</h4>
+<p>The string that should used for any versioning parameters, such as in the media type or URL query parameters.</p>
+<p>Default: <code>'version'</code></p>
+<hr />
<h2 id="authentication-settings">Authentication settings</h2>
<p><em>The following settings control the behavior of unauthenticated requests.</em></p>
<h4 id="unauthenticated_user">UNAUTHENTICATED_USER</h4>
@@ -661,7 +668,7 @@ If set to <code>None</code> then generic filtering is disabled.</p>
<p>A string representing the function that should be used when returning a response for any given exception. If the function returns <code>None</code>, a 500 error will be raised.</p>
<p>This setting can be changed to support error responses other than the default <code>{"detail": "Failure..."}</code> responses. For example, you can use it to provide API responses like <code>{"errors": [{"message": "Failure...", "code": ""} ...]}</code>.</p>
<p>This should be a function with the following signature:</p>
-<pre><code>exception_handler(exc)
+<pre><code>exception_handler(exc, context)
</code></pre>
<ul>
<li><code>exc</code>: The exception.</li>
diff --git a/api-guide/status-codes/index.html b/api-guide/status-codes/index.html
index 2e503c0a..4aa7c5dc 100644
--- a/api-guide/status-codes/index.html
+++ b/api-guide/status-codes/index.html
@@ -189,6 +189,10 @@
</li>
<li >
+ <a href="../versioning">Versioning</a>
+ </li>
+
+ <li >
<a href="../content-negotiation">Content negotiation</a>
</li>
@@ -232,6 +236,10 @@
</li>
<li >
+ <a href="../../topics/internationalization">Internationalization</a>
+ </li>
+
+ <li >
<a href="../../topics/ajax-csrf-cors">AJAX, CSRF & CORS</a>
</li>
@@ -260,23 +268,11 @@
</li>
<li >
- <a href="../../topics/rest-framework-2-announcement">2.0 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.2-announcement">2.2 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.3-announcement">2.3 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.4-announcement">2.4 Announcement</a>
+ <a href="../../topics/3.0-announcement">3.0 Announcement</a>
</li>
<li >
- <a href="../../topics/3.0-announcement">3.0 Announcement</a>
+ <a href="../../topics/3.1-announcement">3.1 Announcement</a>
</li>
<li >
@@ -287,10 +283,6 @@
<a href="../../topics/release-notes">Release Notes</a>
</li>
- <li >
- <a href="../../topics/credits">Credits</a>
- </li>
-
</ul>
</li>
diff --git a/api-guide/testing/index.html b/api-guide/testing/index.html
index 650fc53e..19407551 100644
--- a/api-guide/testing/index.html
+++ b/api-guide/testing/index.html
@@ -189,6 +189,10 @@
</li>
<li >
+ <a href="../versioning">Versioning</a>
+ </li>
+
+ <li >
<a href="../content-negotiation">Content negotiation</a>
</li>
@@ -232,6 +236,10 @@
</li>
<li >
+ <a href="../../topics/internationalization">Internationalization</a>
+ </li>
+
+ <li >
<a href="../../topics/ajax-csrf-cors">AJAX, CSRF & CORS</a>
</li>
@@ -260,23 +268,11 @@
</li>
<li >
- <a href="../../topics/rest-framework-2-announcement">2.0 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.2-announcement">2.2 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.3-announcement">2.3 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.4-announcement">2.4 Announcement</a>
+ <a href="../../topics/3.0-announcement">3.0 Announcement</a>
</li>
<li >
- <a href="../../topics/3.0-announcement">3.0 Announcement</a>
+ <a href="../../topics/3.1-announcement">3.1 Announcement</a>
</li>
<li >
@@ -287,10 +283,6 @@
<a href="../../topics/release-notes">Release Notes</a>
</li>
- <li >
- <a href="../../topics/credits">Credits</a>
- </li>
-
</ul>
</li>
@@ -469,7 +461,7 @@
<h1 id="apirequestfactory">APIRequestFactory</h1>
<p>Extends <a href="https://docs.djangoproject.com/en/dev/topics/testing/advanced/#django.test.client.RequestFactory">Django's existing <code>RequestFactory</code> class</a>.</p>
<h2 id="creating-test-requests">Creating test requests</h2>
-<p>The <code>APIRequestFactory</code> class supports an almost identical API to Django's standard <code>RequestFactory</code> class. This means the that standard <code>.get()</code>, <code>.post()</code>, <code>.put()</code>, <code>.patch()</code>, <code>.delete()</code>, <code>.head()</code> and <code>.options()</code> methods are all available.</p>
+<p>The <code>APIRequestFactory</code> class supports an almost identical API to Django's standard <code>RequestFactory</code> class. This means that the standard <code>.get()</code>, <code>.post()</code>, <code>.put()</code>, <code>.patch()</code>, <code>.delete()</code>, <code>.head()</code> and <code>.options()</code> methods are all available.</p>
<pre><code>from rest_framework.test import APIRequestFactory
# Using the standard RequestFactory API to create a form POST request
@@ -506,7 +498,9 @@ request = factory.put('/notes/547/', content, content_type=content_type)
<h2 id="forcing-authentication">Forcing authentication</h2>
<p>When testing views directly using a request factory, it's often convenient to be able to directly authenticate the request, rather than having to construct the correct authentication credentials.</p>
<p>To forcibly authenticate a request, use the <code>force_authenticate()</code> method.</p>
-<pre><code>factory = APIRequestFactory()
+<pre><code>from rest_framework.tests import force_authenticate
+
+factory = APIRequestFactory()
user = User.objects.get(username='olivia')
view = AccountDetail.as_view()
@@ -538,9 +532,9 @@ response = view(request)
<p><strong>Note</strong>: It's worth noting that Django's standard <code>RequestFactory</code> doesn't need to include this option, because when using regular Django the CSRF validation takes place in middleware, which is not run when testing views directly. When using REST framework, CSRF validation takes place inside the view, so the request factory needs to disable view-level CSRF checks.</p>
<hr />
<h1 id="apiclient">APIClient</h1>
-<p>Extends <a href="https://docs.djangoproject.com/en/dev/topics/testing/overview/#module-django.test.client">Django's existing <code>Client</code> class</a>.</p>
+<p>Extends <a href="https://docs.djangoproject.com/en/dev/topics/testing/tools/#the-test-client">Django's existing <code>Client</code> class</a>.</p>
<h2 id="making-requests">Making requests</h2>
-<p>The <code>APIClient</code> class supports the same request interface as <code>APIRequestFactory</code>. This means the that standard <code>.get()</code>, <code>.post()</code>, <code>.put()</code>, <code>.patch()</code>, <code>.delete()</code>, <code>.head()</code> and <code>.options()</code> methods are all available. For example:</p>
+<p>The <code>APIClient</code> class supports the same request interface as Django's standard <code>Client</code> class. This means the that standard <code>.get()</code>, <code>.post()</code>, <code>.put()</code>, <code>.patch()</code>, <code>.delete()</code>, <code>.head()</code> and <code>.options()</code> methods are all available. For example:</p>
<pre><code>from rest_framework.test import APIClient
client = APIClient()
@@ -646,13 +640,13 @@ self.assertEqual(response.content, '{"username": "lauren", "id": 4}')
</code></pre>
<h2 id="setting-the-available-formats">Setting the available formats</h2>
<p>If you need to test requests using something other than multipart or json requests, you can do so by setting the <code>TEST_REQUEST_RENDERER_CLASSES</code> setting.</p>
-<p>For example, to add support for using <code>format='yaml'</code> in test requests, you might have something like this in your <code>settings.py</code> file.</p>
+<p>For example, to add support for using <code>format='html'</code> in test requests, you might have something like this in your <code>settings.py</code> file.</p>
<pre><code>REST_FRAMEWORK = {
...
'TEST_REQUEST_RENDERER_CLASSES': (
'rest_framework.renderers.MultiPartRenderer',
'rest_framework.renderers.JSONRenderer',
- 'rest_framework.renderers.YAMLRenderer'
+ 'rest_framework.renderers.TemplateHTMLRenderer'
)
}
</code></pre>
diff --git a/api-guide/throttling/index.html b/api-guide/throttling/index.html
index 7db58e4c..6d65c948 100644
--- a/api-guide/throttling/index.html
+++ b/api-guide/throttling/index.html
@@ -189,6 +189,10 @@
</li>
<li >
+ <a href="../versioning">Versioning</a>
+ </li>
+
+ <li >
<a href="../content-negotiation">Content negotiation</a>
</li>
@@ -232,6 +236,10 @@
</li>
<li >
+ <a href="../../topics/internationalization">Internationalization</a>
+ </li>
+
+ <li >
<a href="../../topics/ajax-csrf-cors">AJAX, CSRF & CORS</a>
</li>
@@ -260,23 +268,11 @@
</li>
<li >
- <a href="../../topics/rest-framework-2-announcement">2.0 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.2-announcement">2.2 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.3-announcement">2.3 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.4-announcement">2.4 Announcement</a>
+ <a href="../../topics/3.0-announcement">3.0 Announcement</a>
</li>
<li >
- <a href="../../topics/3.0-announcement">3.0 Announcement</a>
+ <a href="../../topics/3.1-announcement">3.1 Announcement</a>
</li>
<li >
@@ -287,10 +283,6 @@
<a href="../../topics/release-notes">Release Notes</a>
</li>
- <li >
- <a href="../../topics/credits">Credits</a>
- </li>
-
</ul>
</li>
diff --git a/api-guide/validators/index.html b/api-guide/validators/index.html
index 525cea8a..395fd9de 100644
--- a/api-guide/validators/index.html
+++ b/api-guide/validators/index.html
@@ -189,6 +189,10 @@
</li>
<li >
+ <a href="../versioning">Versioning</a>
+ </li>
+
+ <li >
<a href="../content-negotiation">Content negotiation</a>
</li>
@@ -232,6 +236,10 @@
</li>
<li >
+ <a href="../../topics/internationalization">Internationalization</a>
+ </li>
+
+ <li >
<a href="../../topics/ajax-csrf-cors">AJAX, CSRF & CORS</a>
</li>
@@ -260,23 +268,11 @@
</li>
<li >
- <a href="../../topics/rest-framework-2-announcement">2.0 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.2-announcement">2.2 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.3-announcement">2.3 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.4-announcement">2.4 Announcement</a>
+ <a href="../../topics/3.0-announcement">3.0 Announcement</a>
</li>
<li >
- <a href="../../topics/3.0-announcement">3.0 Announcement</a>
+ <a href="../../topics/3.1-announcement">3.1 Announcement</a>
</li>
<li >
@@ -287,10 +283,6 @@
<a href="../../topics/release-notes">Release Notes</a>
</li>
- <li >
- <a href="../../topics/credits">Credits</a>
- </li>
-
</ul>
</li>
diff --git a/api-guide/versioning/index.html b/api-guide/versioning/index.html
new file mode 100644
index 00000000..8a29d0ea
--- /dev/null
+++ b/api-guide/versioning/index.html
@@ -0,0 +1,612 @@
+<!DOCTYPE html>
+<html lang="en">
+
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <meta charset="utf-8">
+ <title>Versioning - Django REST framework</title>
+ <link href="../../img/favicon.ico" rel="icon" type="image/x-icon">
+ <link rel="canonical" href="http://www.django-rest-framework.org/api-guide/versioning/" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="description" content="Django, API, REST, Versioning">
+ <meta name="author" content="Tom Christie">
+
+ <!-- Le styles -->
+ <link href="../../css/prettify.css" rel="stylesheet">
+ <link href="../../css/bootstrap.css" rel="stylesheet">
+ <link href="../../css/bootstrap-responsive.css" rel="stylesheet">
+ <link href="../../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>
+
+ <style>
+ span.fusion-wrap a {
+ display: block;
+ margin-top: 10px;
+ color: black;
+ }
+ a.fusion-poweredby {
+ display: block;
+ margin-top: 10px;
+ }
+ @media (max-width: 767px) {
+ div.promo {
+ display: none;
+ }
+ }
+ </style>
+</head>
+<body onload="prettyPrint()" class="-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 " rel="prev" href="../content-negotiation">
+ Next <i class="icon-arrow-right icon-white"></i>
+ </a>
+ <a class="repo-link btn btn-inverse btn-small " rel="next" href="../pagination">
+ <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://www.django-rest-framework.org">Django REST framework</a>
+ <div class="nav-collapse collapse">
+
+ <!-- Main navigation -->
+ <ul class="nav navbar-nav">
+ <li ><a href="/">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="../../tutorial/quickstart">Quickstart</a>
+ </li>
+
+ <li >
+ <a href="../../tutorial/1-serialization">1 - Serialization</a>
+ </li>
+
+ <li >
+ <a href="../../tutorial/2-requests-and-responses">2 - Requests and responses</a>
+ </li>
+
+ <li >
+ <a href="../../tutorial/3-class-based-views">3 - Class based views</a>
+ </li>
+
+ <li >
+ <a href="../../tutorial/4-authentication-and-permissions">4 - Authentication and permissions</a>
+ </li>
+
+ <li >
+ <a href="../../tutorial/5-relationships-and-hyperlinked-apis">5 - Relationships and hyperlinked APIs</a>
+ </li>
+
+ <li >
+ <a href="../../tutorial/6-viewsets-and-routers">6 - Viewsets and routers</a>
+ </li>
+
+ </ul>
+ </li>
+
+ <li class="dropdown active">
+ <a href="#" class="dropdown-toggle" data-toggle="dropdown">API Guide <b class="caret"></b></a>
+ <ul class="dropdown-menu">
+
+ <li >
+ <a href="../requests">Requests</a>
+ </li>
+
+ <li >
+ <a href="../responses">Responses</a>
+ </li>
+
+ <li >
+ <a href="../views">Views</a>
+ </li>
+
+ <li >
+ <a href="../generic-views">Generic views</a>
+ </li>
+
+ <li >
+ <a href="../viewsets">Viewsets</a>
+ </li>
+
+ <li >
+ <a href="../routers">Routers</a>
+ </li>
+
+ <li >
+ <a href="../parsers">Parsers</a>
+ </li>
+
+ <li >
+ <a href="../renderers">Renderers</a>
+ </li>
+
+ <li >
+ <a href="../serializers">Serializers</a>
+ </li>
+
+ <li >
+ <a href="../fields">Serializer fields</a>
+ </li>
+
+ <li >
+ <a href="../relations">Serializer relations</a>
+ </li>
+
+ <li >
+ <a href="../validators">Validators</a>
+ </li>
+
+ <li >
+ <a href="../authentication">Authentication</a>
+ </li>
+
+ <li >
+ <a href="../permissions">Permissions</a>
+ </li>
+
+ <li >
+ <a href="../throttling">Throttling</a>
+ </li>
+
+ <li >
+ <a href="../filtering">Filtering</a>
+ </li>
+
+ <li >
+ <a href="../pagination">Pagination</a>
+ </li>
+
+ <li class="active" >
+ <a href=".">Versioning</a>
+ </li>
+
+ <li >
+ <a href="../content-negotiation">Content negotiation</a>
+ </li>
+
+ <li >
+ <a href="../metadata">Metadata</a>
+ </li>
+
+ <li >
+ <a href="../format-suffixes">Format suffixes</a>
+ </li>
+
+ <li >
+ <a href="../reverse">Returning URLs</a>
+ </li>
+
+ <li >
+ <a href="../exceptions">Exceptions</a>
+ </li>
+
+ <li >
+ <a href="../status-codes">Status codes</a>
+ </li>
+
+ <li >
+ <a href="../testing">Testing</a>
+ </li>
+
+ <li >
+ <a href="../settings">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="../../topics/documenting-your-api">Documenting your API</a>
+ </li>
+
+ <li >
+ <a href="../../topics/internationalization">Internationalization</a>
+ </li>
+
+ <li >
+ <a href="../../topics/ajax-csrf-cors">AJAX, CSRF & CORS</a>
+ </li>
+
+ <li >
+ <a href="../../topics/browser-enhancements">Browser enhancements</a>
+ </li>
+
+ <li >
+ <a href="../../topics/browsable-api">The Browsable API</a>
+ </li>
+
+ <li >
+ <a href="../../topics/rest-hypermedia-hateoas">REST, Hypermedia & HATEOAS</a>
+ </li>
+
+ <li >
+ <a href="../../topics/third-party-resources">Third Party Resources</a>
+ </li>
+
+ <li >
+ <a href="../../topics/contributing">Contributing to REST framework</a>
+ </li>
+
+ <li >
+ <a href="../../topics/project-management">Project management</a>
+ </li>
+
+ <li >
+ <a href="../../topics/3.0-announcement">3.0 Announcement</a>
+ </li>
+
+ <li >
+ <a href="../../topics/3.1-announcement">3.1 Announcement</a>
+ </li>
+
+ <li >
+ <a href="../../topics/kickstarter-announcement">Kickstarter Announcement</a>
+ </li>
+
+ <li >
+ <a href="../../topics/release-notes">Release Notes</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">&times;</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">&laquo; previous</a>
+ <a class="btn btn-mini btn-primary" style="float: right; margin-right: 8px; width: 60px;">next &raquo;</a>
+ </p>
+ -->
+ <div id="table-of-contents">
+ <ul class="nav nav-list side-nav well sidebar-nav-fixed">
+
+
+
+
+
+ <li class="main">
+ <a href="#versioning">Versioning</a>
+ </li>
+
+
+ <li>
+ <a href="#versioning-with-rest-framework">Versioning with REST framework</a>
+ </li>
+
+ <li>
+ <a href="#configuring-the-versioning-scheme">Configuring the versioning scheme</a>
+ </li>
+
+
+
+
+ <li class="main">
+ <a href="#api-reference">API Reference</a>
+ </li>
+
+
+ <li>
+ <a href="#acceptheaderversioning">AcceptHeaderVersioning</a>
+ </li>
+
+ <li>
+ <a href="#urlparameterversioning">URLParameterVersioning</a>
+ </li>
+
+ <li>
+ <a href="#namespaceversioning">NamespaceVersioning</a>
+ </li>
+
+ <li>
+ <a href="#hostnameversioning">HostNameVersioning</a>
+ </li>
+
+ <li>
+ <a href="#queryparameterversioning">QueryParameterVersioning</a>
+ </li>
+
+
+
+
+ <li class="main">
+ <a href="#custom-versioning-schemes">Custom versioning schemes</a>
+ </li>
+
+
+ <li>
+ <a href="#example">Example</a>
+ </li>
+
+
+
+
+
+
+ </ul>
+
+ </div>
+ </div>
+
+ <div id="main-content" class="span9">
+
+
+ <a class="github" href="https://github.com/tomchristie/django-rest-framework/tree/master/rest_framework/versioning.py">
+ <span class="label label-info">versioning.py</span>
+ </a>
+
+
+
+ <h1 id="versioning">Versioning</h1>
+<blockquote>
+<p>Versioning an interface is just a "polite" way to kill deployed clients.</p>
+<p>&mdash; <a href="http://www.slideshare.net/evolve_conference/201308-fielding-evolve/31">Roy Fielding</a>.</p>
+</blockquote>
+<p>API versioning allows you to alter behavior between different clients. REST framework provides for a number of different versioning schemes.</p>
+<p>Versioning is determined by the incoming client request, and may either be based on the request URL, or based on the request headers.</p>
+<p>There are a number of valid approaches to approaching versioning. <a href="http://www.infoq.com/articles/roy-fielding-on-versioning">Non-versioned systems can also be appropriate</a>, particularly if you're engineering for very long-term systems with multiple clients outside of your control.</p>
+<h2 id="versioning-with-rest-framework">Versioning with REST framework</h2>
+<p>When API versioning is enabled, the <code>request.version</code> attribute will contain a string that corresponds to the version requested in the incoming client request.</p>
+<p>By default, versioning is not enabled, and <code>request.version</code> will always return <code>None</code>.</p>
+<h4 id="varying-behavior-based-on-the-version">Varying behavior based on the version</h4>
+<p>How you vary the API behavior is up to you, but one example you might typically want is to switch to a different serialization style in a newer version. For example:</p>
+<pre><code>def get_serializer_class(self):
+ if self.request.version == 'v1':
+ return AccountSerializerVersion1
+ return AccountSerializer
+</code></pre>
+<h4 id="reversing-urls-for-versioned-apis">Reversing URLs for versioned APIs</h4>
+<p>The <code>reverse</code> function included by REST framework ties in with the versioning scheme. You need to make sure to include the current <code>request</code> as a keyword argument, like so.</p>
+<pre><code>reverse('bookings-list', request=request)
+</code></pre>
+<p>The above function will apply any URL transformations appropriate to the request version. For example:</p>
+<ul>
+<li>If <code>NamespacedVersioning</code> was being used, and the API version was 'v1', then the URL lookup used would be <code>'v1:bookings-list'</code>, which might resolve to a URL like <code>http://example.org/v1/bookings/</code>.</li>
+<li>If <code>QueryParameterVersioning</code> was being used, and the API version was <code>1.0</code>, then the returned URL might be something like <code>http://example.org/bookings/?version=1.0</code></li>
+</ul>
+<h4 id="versioned-apis-and-hyperlinked-serializers">Versioned APIs and hyperlinked serializers</h4>
+<p>When using hyperlinked serialization styles together with a URL based versioning scheme make sure to include the request as context to the serializer.</p>
+<pre><code>def get(self, request):
+ queryset = Booking.objects.all()
+ serializer = BookingsSerializer(queryset, many=True, context={'request': request})
+ return Response({'all_bookings': serializer.data})
+</code></pre>
+<p>Doing so will allow any returned URLs to include the appropriate versioning.</p>
+<h2 id="configuring-the-versioning-scheme">Configuring the versioning scheme</h2>
+<p>The versioning scheme is defined by the <code>DEFAULT_VERSIONING_CLASS</code> settings key.</p>
+<pre><code>REST_FRAMEWORK = {
+ 'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.NamespaceVersioning'
+}
+</code></pre>
+<p>Unless it is explicitly set, the value for <code>DEFAULT_VERSIONING_CLASS</code> will be <code>None</code>. In this case the <code>request.version</code> attribute will always return <code>None</code>.</p>
+<p>You can also set the versioning scheme on an individual view. Typically you won't need to do this, as it makes more sense to have a single versioning scheme used globally. If you do need to do so, use the <code>versioning_class</code> attribute.</p>
+<pre><code>class ProfileList(APIView):
+ versioning_class = versioning.QueryParameterVersioning
+</code></pre>
+<h4 id="other-versioning-settings">Other versioning settings</h4>
+<p>The following settings keys are also used to control versioning:</p>
+<ul>
+<li><code>DEFAULT_VERSION</code>. The value that should be used for <code>request.version</code> when no versioning information is present. Defaults to <code>None</code>.</li>
+<li><code>ALLOWED_VERSIONS</code>. If set, this value will restrict the set of versions that may be returned by the versioning scheme, and will raise an error if the provided version if not in this set. Defaults to <code>None</code>.</li>
+<li><code>VERSION_PARAMETER</code>. The string that should used for any versioning parameters, such as in the media type or URL query parameters. Defaults to <code>'version'</code>.</li>
+</ul>
+<hr />
+<h1 id="api-reference">API Reference</h1>
+<h2 id="acceptheaderversioning">AcceptHeaderVersioning</h2>
+<p>This scheme requires the client to specify the version as part of the media type in the <code>Accept</code> header. The version is included as a media type parameter, that supplements the main media type.</p>
+<p>Here's an example HTTP request using the accept header versioning style.</p>
+<pre><code>GET /bookings/ HTTP/1.1
+Host: example.com
+Accept: application/json; version=1.0
+</code></pre>
+<p>In the example request above <code>request.version</code> attribute would return the string <code>'1.0'</code>.</p>
+<p>Versioning based on accept headers is <a href="http://blog.steveklabnik.com/posts/2011-07-03-nobody-understands-rest-or-http#i_want_my_api_to_be_versioned">generally considered</a> as <a href="https://github.com/interagent/http-api-design#version-with-accepts-header">best practice</a>, although other styles may be suitable depending on your client requirements.</p>
+<h4 id="using-accept-headers-with-vendor-media-types">Using accept headers with vendor media types</h4>
+<p>Strictly speaking the <code>json</code> media type is not specified as <a href="http://tools.ietf.org/html/rfc4627#section-6">including additional parameters</a>. If you are building a well-specified public API you might consider using a <a href="http://en.wikipedia.org/wiki/Internet_media_type#Vendor_tree">vendor media type</a>. To do so, configure your renderers to use a JSON based renderer with a custom media type:</p>
+<pre><code>class BookingsAPIRenderer(JSONRenderer):
+ media_type = 'application/vnd.megacorp.bookings+json'
+</code></pre>
+<p>Your client requests would now look like this:</p>
+<pre><code>GET /bookings/ HTTP/1.1
+Host: example.com
+Accept: application/vnd.megacorp.bookings+json; version=1.0
+</code></pre>
+<h2 id="urlparameterversioning">URLParameterVersioning</h2>
+<p>This scheme requires the client to specify the version as part of the URL path.</p>
+<pre><code>GET /v1/bookings/ HTTP/1.1
+Host: example.com
+Accept: application/json
+</code></pre>
+<p>Your URL conf must include a pattern that matches the version with a <code>'version'</code> keyword argument, so that this information is available to the versioning scheme.</p>
+<pre><code>urlpatterns = [
+ url(
+ r'^(?P&lt;version&gt;{v1,v2})/bookings/$',
+ bookings_list,
+ name='bookings-list'
+ ),
+ url(
+ r'^(?P&lt;version&gt;{v1,v2})/bookings/(?P&lt;pk&gt;[0-9]+)/$',
+ bookings_detail,
+ name='bookings-detail'
+ )
+]
+</code></pre>
+<h2 id="namespaceversioning">NamespaceVersioning</h2>
+<p>To the client, this scheme is the same as <code>URLParameterVersioning</code>. The only difference is how it is configured in your Django application, as it uses URL namespacing, instead of URL keyword arguments.</p>
+<pre><code>GET /v1/something/ HTTP/1.1
+Host: example.com
+Accept: application/json
+</code></pre>
+<p>With this scheme the <code>request.version</code> attribute is determined based on the <code>namespace</code> that matches the incoming request path.</p>
+<p>In the following example we're giving a set of views two different possible URL prefixes, each under a different namespace:</p>
+<pre><code># bookings/urls.py
+urlpatterns = [
+ url(r'^$', bookings_list, name='bookings-list'),
+ url(r'^(?P&lt;pk&gt;[0-9]+)/$', bookings_detail, name='bookings-detail')
+]
+
+# urls.py
+urlpatterns = [
+ url(r'^v1/bookings/', include('bookings.urls', namespace='v1')),
+ url(r'^v2/bookings/', include('bookings.urls', namespace='v2'))
+]
+</code></pre>
+<p>Both <code>URLParameterVersioning</code> and <code>NamespaceVersioning</code> are reasonable if you just need a simple versioning scheme. The <code>URLParameterVersioning</code> approach might be better suitable for small ad-hoc projects, and the <code>NamespaceVersioning</code> is probably easier to manage for larger projects.</p>
+<h2 id="hostnameversioning">HostNameVersioning</h2>
+<p>The hostname versioning scheme requires the client to specify the requested version as part of the hostname in the URL.</p>
+<p>For example the following is an HTTP request to the <code>http://v1.example.com/bookings/</code> URL:</p>
+<pre><code>GET /bookings/ HTTP/1.1
+Host: v1.example.com
+Accept: application/json
+</code></pre>
+<p>By default this implementation expects the hostname to match this simple regular expression:</p>
+<pre><code>^([a-zA-Z0-9]+)\.[a-zA-Z0-9]+\.[a-zA-Z0-9]+$
+</code></pre>
+<p>Note that the first group is enclosed in brackets, indicating that this is the matched portion of the hostname.</p>
+<p>The <code>HostNameVersioning</code> scheme can be awkward to use in debug mode as you will typically be accessing a raw IP address such as <code>127.0.0.1</code>. There are various online services which you to <a href="https://reinteractive.net/posts/199-developing-and-testing-rails-applications-with-subdomains">access localhost with a custom subdomain</a> which you may find helpful in this case.</p>
+<p>Hostname based versioning can be particularly useful if you have requirements to route incoming requests to different servers based on the version, as you can configure different DNS records for different API versions.</p>
+<h2 id="queryparameterversioning">QueryParameterVersioning</h2>
+<p>This scheme is a simple style that includes the version as a query parameter in the URL. For example:</p>
+<pre><code>GET /something/?version=0.1 HTTP/1.1
+Host: example.com
+Accept: application/json
+</code></pre>
+<hr />
+<h1 id="custom-versioning-schemes">Custom versioning schemes</h1>
+<p>To implement a custom versioning scheme, subclass <code>BaseVersioning</code> and override the <code>.determine_version</code> method.</p>
+<h2 id="example">Example</h2>
+<p>The following example uses a custom <code>X-API-Version</code> header to determine the requested version.</p>
+<pre><code>class XAPIVersionScheme(versioning.BaseVersioning):
+ def determine_version(self, request, *args, **kwargs):
+ return request.META.get('HTTP_X_API_VERSION', None)
+</code></pre>
+<p>If your versioning scheme is based on the request URL, you will also want to alter how versioned URLs are determined. In order to do so you should override the <code>.reverse()</code> method on the class. See the source code for examples.</p>
+
+ </div>
+ <!--/span-->
+ </div>
+ <!--/row-->
+ </div>
+ <!--/.fluid-container-->
+ </div>
+ <!--/.body content-->
+ <div id="push"></div>
+ </div>
+ <!--/.wrapper -->
+
+ <footer class="span12">
+ <p>Documentation built with <a href="http://www.mkdocs.org/">MkDocs</a>.</a>
+ </p>
+ </footer>
+
+ <!-- Le javascript
+ ================================================== -->
+ <!-- Placed at the end of the document so the pages load faster -->
+ <script src="../../js/jquery-1.8.1-min.js"></script>
+ <script src="../../js/prettify-1.0.js"></script>
+ <script src="../../js/bootstrap-2.1.1-min.js"></script>
+ <script src="../../js/theme.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> \ No newline at end of file
diff --git a/api-guide/views/index.html b/api-guide/views/index.html
index f07a4921..09a1de41 100644
--- a/api-guide/views/index.html
+++ b/api-guide/views/index.html
@@ -189,6 +189,10 @@
</li>
<li >
+ <a href="../versioning">Versioning</a>
+ </li>
+
+ <li >
<a href="../content-negotiation">Content negotiation</a>
</li>
@@ -232,6 +236,10 @@
</li>
<li >
+ <a href="../../topics/internationalization">Internationalization</a>
+ </li>
+
+ <li >
<a href="../../topics/ajax-csrf-cors">AJAX, CSRF & CORS</a>
</li>
@@ -260,23 +268,11 @@
</li>
<li >
- <a href="../../topics/rest-framework-2-announcement">2.0 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.2-announcement">2.2 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.3-announcement">2.3 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.4-announcement">2.4 Announcement</a>
+ <a href="../../topics/3.0-announcement">3.0 Announcement</a>
</li>
<li >
- <a href="../../topics/3.0-announcement">3.0 Announcement</a>
+ <a href="../../topics/3.1-announcement">3.1 Announcement</a>
</li>
<li >
@@ -287,10 +283,6 @@
<a href="../../topics/release-notes">Release Notes</a>
</li>
- <li >
- <a href="../../topics/credits">Credits</a>
- </li>
-
</ul>
</li>
diff --git a/api-guide/viewsets/index.html b/api-guide/viewsets/index.html
index 7029dc8d..954f49eb 100644
--- a/api-guide/viewsets/index.html
+++ b/api-guide/viewsets/index.html
@@ -189,6 +189,10 @@
</li>
<li >
+ <a href="../versioning">Versioning</a>
+ </li>
+
+ <li >
<a href="../content-negotiation">Content negotiation</a>
</li>
@@ -232,6 +236,10 @@
</li>
<li >
+ <a href="../../topics/internationalization">Internationalization</a>
+ </li>
+
+ <li >
<a href="../../topics/ajax-csrf-cors">AJAX, CSRF & CORS</a>
</li>
@@ -260,23 +268,11 @@
</li>
<li >
- <a href="../../topics/rest-framework-2-announcement">2.0 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.2-announcement">2.2 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.3-announcement">2.3 Announcement</a>
- </li>
-
- <li >
- <a href="../../topics/2.4-announcement">2.4 Announcement</a>
+ <a href="../../topics/3.0-announcement">3.0 Announcement</a>
</li>
<li >
- <a href="../../topics/3.0-announcement">3.0 Announcement</a>
+ <a href="../../topics/3.1-announcement">3.1 Announcement</a>
</li>
<li >
@@ -287,10 +283,6 @@
<a href="../../topics/release-notes">Release Notes</a>
</li>
- <li >
- <a href="../../topics/credits">Credits</a>
- </li>
-
</ul>
</li>
@@ -566,7 +558,7 @@ class UserViewSet(viewsets.ModelViewSet):
<p>The <code>ModelViewSet</code> class inherits from <code>GenericAPIView</code> and includes implementations for various actions, by mixing in the behavior of the various mixin classes.</p>
<p>The actions provided by the <code>ModelViewSet</code> class are <code>.list()</code>, <code>.retrieve()</code>, <code>.create()</code>, <code>.update()</code>, and <code>.destroy()</code>.</p>
<h4 id="example_1">Example</h4>
-<p>Because <code>ModelViewSet</code> extends <code>GenericAPIView</code>, you'll normally need to provide at least the <code>queryset</code> and <code>serializer_class</code> attributes, or the <code>model</code> attribute shortcut. For example:</p>
+<p>Because <code>ModelViewSet</code> extends <code>GenericAPIView</code>, you'll normally need to provide at least the <code>queryset</code> and <code>serializer_class</code> attributes. For example:</p>
<pre><code>class AccountViewSet(viewsets.ModelViewSet):
"""
A simple ViewSet for viewing and editing accounts.