aboutsummaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rwxr-xr-xdocs/api-guide/authentication.md99
-rw-r--r--docs/api-guide/exceptions.md20
-rw-r--r--docs/api-guide/parsers.md36
-rw-r--r--docs/api-guide/permissions.md17
-rw-r--r--docs/api-guide/renderers.md84
-rw-r--r--docs/api-guide/serializers.md63
-rw-r--r--docs/api-guide/settings.md28
-rw-r--r--docs/api-guide/testing.md4
-rw-r--r--docs/api-guide/versioning.md202
-rw-r--r--docs/index.md17
-rw-r--r--docs/tutorial/2-requests-and-responses.md2
11 files changed, 328 insertions, 244 deletions
diff --git a/docs/api-guide/authentication.md b/docs/api-guide/authentication.md
index b04858e3..2074f1bf 100755
--- a/docs/api-guide/authentication.md
+++ b/docs/api-guide/authentication.md
@@ -249,105 +249,6 @@ Unauthenticated responses that are denied permission will result in an `HTTP 403
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 `PUT`, `PATCH`, `POST` or `DELETE` requests. See the [Django CSRF documentation][csrf-ajax] for more details.
-## OAuthAuthentication
-
-This authentication uses [OAuth 1.0a][oauth-1.0a] 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.
-
-This authentication class depends on the optional `django-oauth-plus` and `oauth2` packages. In order to make it work you must install these packages and add `oauth_provider` to your `INSTALLED_APPS`:
-
- INSTALLED_APPS = (
- ...
- `oauth_provider`,
- )
-
-Don't forget to run `syncdb` once you've added the package.
-
- python manage.py syncdb
-
-#### Getting started with django-oauth-plus
-
-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.
-
-The `django-oauth-plus` package provides simple foundation for classic 'three-legged' oauth flow. Please refer to [the documentation][django-oauth-plus] for more details.
-
-## OAuth2Authentication
-
-This authentication uses [OAuth 2.0][rfc6749] 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.
-
-This authentication class depends on the optional [django-oauth2-provider][django-oauth2-provider] project. In order to make it work you must install this package and add `provider` and `provider.oauth2` to your `INSTALLED_APPS`:
-
- INSTALLED_APPS = (
- ...
- 'provider',
- 'provider.oauth2',
- )
-
-Then add `OAuth2Authentication` to your global `DEFAULT_AUTHENTICATION` setting:
-
- 'DEFAULT_AUTHENTICATION_CLASSES': (
- 'rest_framework.authentication.OAuth2Authentication',
- ),
-
-You must also include the following in your root `urls.py` module:
-
- url(r'^oauth2/', include('provider.oauth2.urls', namespace='oauth2')),
-
-Note that the `namespace='oauth2'` argument is required.
-
-Finally, sync your database.
-
- python manage.py syncdb
- python manage.py migrate
-
----
-
-**Note:** If you use `OAuth2Authentication` in production you must ensure that your API is only available over `https`.
-
----
-
-#### Getting started with django-oauth2-provider
-
-The `OAuth2Authentication` class only provides token verification for requests. It doesn't provide authorization flow for your clients.
-
-The OAuth 2 authorization flow is taken care by the [django-oauth2-provider][django-oauth2-provider] dependency. A walkthrough is given here, but for more details you should refer to [the documentation][django-oauth2-provider-docs].
-
-To get started:
-
-##### 1. Create a client
-
-You can create a client, either through the shell, or by using the Django admin.
-
-Go to the admin panel and create a new `Provider.Client` entry. It will create the `client_id` and `client_secret` properties for you.
-
-##### 2. Request an access token
-
-To request an access token, submit a `POST` request to the url `/oauth2/access_token` with the following fields:
-
-* `client_id` the client id you've just configured at the previous step.
-* `client_secret` again configured at the previous step.
-* `username` the username with which you want to log in.
-* `password` well, that speaks for itself.
-
-You can use the command line to test that your local configuration is working:
-
- curl -X POST -d "client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&grant_type=password&username=YOUR_USERNAME&password=YOUR_PASSWORD" http://localhost:8000/oauth2/access_token/
-
-You should get a response that looks something like this:
-
- {"access_token": "<your-access-token>", "scope": "read", "expires_in": 86399, "refresh_token": "<your-refresh-token>"}
-
-##### 3. Access the API
-
-The only thing needed to make the `OAuth2Authentication` class work is to insert the `access_token` you've received in the `Authorization` request header.
-
-The command line to test the authentication looks like:
-
- curl -H "Authorization: Bearer <your-access-token>" http://localhost:8000/api/
-
-### Alternative OAuth 2 implementations
-
-Note that [Django OAuth Toolkit][django-oauth-toolkit] is an alternative external package that also includes OAuth 2.0 support for REST framework.
-
---
# Custom authentication
diff --git a/docs/api-guide/exceptions.md b/docs/api-guide/exceptions.md
index 467ad970..50bd14dd 100644
--- a/docs/api-guide/exceptions.md
+++ b/docs/api-guide/exceptions.md
@@ -51,10 +51,10 @@ In order to alter the style of the response, you could write the following custo
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:
@@ -128,6 +128,14 @@ Raised when an authenticated request fails the permission checks.
By default this exception results in a response with the HTTP status code "403 Forbidden".
+## NotFound
+
+**Signature:** `NotFound(detail=None)`
+
+Raised when a resource does not exists at the given URL. This exception is equivalent to the standard `Http404` Django exception.
+
+By default this exception results in a response with the HTTP status code "404 Not Found".
+
## MethodNotAllowed
**Signature:** `MethodNotAllowed(method, detail=None)`
@@ -136,6 +144,14 @@ Raised when an incoming request occurs that does not map to a handler method on
By default this exception results in a response with the HTTP status code "405 Method Not Allowed".
+## NotAcceptable
+
+**Signature:** `NotAcceptable(detail=None)`
+
+Raised when an incoming request occurs with an `Accept` header that cannot be satisfied by any of the available renderers.
+
+By default this exception results in a response with the HTTP status code "406 Not Acceptable".
+
## UnsupportedMediaType
**Signature:** `UnsupportedMediaType(media_type, detail=None)`
diff --git a/docs/api-guide/parsers.md b/docs/api-guide/parsers.md
index 73e3a705..9323d382 100644
--- a/docs/api-guide/parsers.md
+++ b/docs/api-guide/parsers.md
@@ -26,26 +26,26 @@ As an example, if you are sending `json` encoded data using jQuery with the [.aj
## Setting the parsers
-The default set of parsers may be set globally, using the `DEFAULT_PARSER_CLASSES` setting. For example, the following settings would allow requests with `YAML` content.
+The default set of parsers may be set globally, using the `DEFAULT_PARSER_CLASSES` setting. For example, the following settings would allow requests with `JSON` content.
REST_FRAMEWORK = {
'DEFAULT_PARSER_CLASSES': (
- 'rest_framework.parsers.YAMLParser',
+ 'rest_framework.parsers.JSONParser',
)
}
You can also set the parsers used for an individual view, or viewset,
using the `APIView` class based views.
- from rest_framework.parsers import YAMLParser
+ 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})
@@ -53,10 +53,10 @@ using the `APIView` class based views.
Or, if you're using the `@api_view` decorator with function based views.
@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})
@@ -70,26 +70,6 @@ Parses `JSON` request content.
**.media_type**: `application/json`
-## YAMLParser
-
-Parses `YAML` request content.
-
-Requires the `pyyaml` package to be installed.
-
-**.media_type**: `application/yaml`
-
-## XMLParser
-
-Parses REST framework's default style of `XML` request content.
-
-Note that the `XML` markup language is typically used as the base language for more strictly defined domain-specific languages, such as `RSS`, `Atom`, and `XHTML`.
-
-If you are considering using `XML` 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.
-
-Requires the `defusedxml` package to be installed.
-
-**.media_type**: `application/xml`
-
## FormParser
Parses HTML form content. `request.data` will be populated with a `QueryDict` of data.
@@ -161,7 +141,7 @@ By default this will include the following keys: `view`, `request`, `args`, `kwa
## Example
-The following is an example plaintext parser that will populate the `request.data` property with a string representing the body of the request.
+The following is an example plaintext parser that will populate the `request.data` property with a string representing the body of the request.
class PlainTextParser(BaseParser):
"""
diff --git a/docs/api-guide/permissions.md b/docs/api-guide/permissions.md
index 743ca435..8731cab0 100644
--- a/docs/api-guide/permissions.md
+++ b/docs/api-guide/permissions.md
@@ -166,21 +166,6 @@ As with `DjangoModelPermissions` you can use custom model permissions by overrid
---
-## TokenHasReadWriteScope
-
-This permission class is intended for use with either of the `OAuthAuthentication` and `OAuth2Authentication` classes, and ties into the scoping that their backends provide.
-
-Requests with a safe methods of `GET`, `OPTIONS` or `HEAD` will be allowed if the authenticated token has read permission.
-
-Requests for `POST`, `PUT`, `PATCH` and `DELETE` will be allowed if the authenticated token has write permission.
-
-This permission class relies on the implementations of the [django-oauth-plus][django-oauth-plus] and [django-oauth2-provider][django-oauth2-provider] libraries, which both provide limited support for controlling the scope of access tokens:
-
-* `django-oauth-plus`: Tokens are associated with a `Resource` class which has a `name`, `url` and `is_readonly` properties.
-* `django-oauth2-provider`: Tokens are associated with a bitwise `scope` attribute, that defaults to providing bitwise values for `read` and/or `write`.
-
-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 `django-oauth-plus` or `django-oauth2-provider` package for more details on scoping token access.
-
---
# Custom permissions
@@ -268,8 +253,6 @@ The [REST Condition][rest-condition] package is another extension for building c
[objectpermissions]: https://docs.djangoproject.com/en/dev/topics/auth/customizing/#handling-object-permissions
[guardian]: https://github.com/lukaszb/django-guardian
[get_objects_for_user]: http://pythonhosted.org/django-guardian/api/guardian.shortcuts.html#get-objects-for-user
-[django-oauth-plus]: http://code.larlet.fr/django-oauth-plus
-[django-oauth2-provider]: https://github.com/caffeinehit/django-oauth2-provider
[2.2-announcement]: ../topics/2.2-announcement.md
[filtering]: filtering.md
[drf-any-permissions]: https://github.com/kevin-brown/drf-any-permissions
diff --git a/docs/api-guide/renderers.md b/docs/api-guide/renderers.md
index 035ec1d2..69460dbc 100644
--- a/docs/api-guide/renderers.md
+++ b/docs/api-guide/renderers.md
@@ -18,11 +18,11 @@ For more information see the documentation on [content negotiation][conneg].
## Setting the renderers
-The default set of renderers may be set globally, using the `DEFAULT_RENDERER_CLASSES` setting. For example, the following settings would use `YAML` as the main media type and also include the self describing API.
+The default set of renderers may be set globally, using the `DEFAULT_RENDERER_CLASSES` setting. For example, the following settings would use `JSON` as the main media type and also include the self describing API.
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': (
- 'rest_framework.renderers.YAMLRenderer',
+ 'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
)
}
@@ -31,15 +31,15 @@ You can also set the renderers used for an individual view, or viewset,
using the `APIView` class based views.
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()
@@ -49,10 +49,10 @@ using the `APIView` class based views.
Or, if you're using the `@api_view` decorator with function based views.
@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}
@@ -93,72 +93,6 @@ The default JSON encoding style can be altered using the `UNICODE_JSON` and `COM
**.charset**: `None`
-## JSONPRenderer
-
-Renders the request data into `JSONP`. The `JSONP` media type provides a mechanism of allowing cross-domain AJAX requests, by wrapping a `JSON` response in a javascript callback.
-
-The javascript callback function must be set by the client including a `callback` URL query parameter. For example `http://example.com/api/users?callback=jsonpCallback`. If the callback function is not explicitly set by the client it will default to `'callback'`.
-
----
-
-**Warning**: If you require cross-domain AJAX requests, you should almost certainly be using the more modern approach of [CORS][cors] as an alternative to `JSONP`. See the [CORS documentation][cors-docs] for more details.
-
-The `jsonp` approach is essentially a browser hack, and is [only appropriate for globally readable API endpoints][jsonp-security], where `GET` requests are unauthenticated and do not require any user permissions.
-
----
-
-**.media_type**: `application/javascript`
-
-**.format**: `'.jsonp'`
-
-**.charset**: `utf-8`
-
-## YAMLRenderer
-
-Renders the request data into `YAML`.
-
-Requires the `pyyaml` package to be installed.
-
-Note that non-ascii characters will be rendered using `\uXXXX` character escape. For example:
-
- unicode black star: "\u2605"
-
-**.media_type**: `application/yaml`
-
-**.format**: `'.yaml'`
-
-**.charset**: `utf-8`
-
-## UnicodeYAMLRenderer
-
-Renders the request data into `YAML`.
-
-Requires the `pyyaml` package to be installed.
-
-Note that non-ascii characters will not be character escaped. For example:
-
- unicode black star: ★
-
-**.media_type**: `application/yaml`
-
-**.format**: `'.yaml'`
-
-**.charset**: `utf-8`
-
-## XMLRenderer
-
-Renders REST framework's default style of `XML` response content.
-
-Note that the `XML` markup language is used typically used as the base language for more strictly defined domain-specific languages, such as `RSS`, `Atom`, and `XHTML`.
-
-If you are considering using `XML` 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.
-
-**.media_type**: `application/xml`
-
-**.format**: `'.xml'`
-
-**.charset**: `utf-8`
-
## TemplateHTMLRenderer
Renders data to HTML, using Django's standard template rendering.
@@ -433,10 +367,6 @@ Comma-separated values are a plain-text tabular data format, that can be easily
[cite]: https://docs.djangoproject.com/en/dev/ref/template-response/#the-rendering-process
[conneg]: content-negotiation.md
[browser-accept-headers]: http://www.gethifi.com/blog/browser-rest-http-accept-headers
-[rfc4627]: http://www.ietf.org/rfc/rfc4627.txt
-[cors]: http://www.w3.org/TR/cors/
-[cors-docs]: ../topics/ajax-csrf-cors.md
-[jsonp-security]: http://stackoverflow.com/questions/613962/is-jsonp-safe-to-use
[testing]: testing.md
[HATEOAS]: http://timelessrepo.com/haters-gonna-hateoas
[quote]: http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven
diff --git a/docs/api-guide/serializers.md b/docs/api-guide/serializers.md
index f88ec51f..9a9d5032 100644
--- a/docs/api-guide/serializers.md
+++ b/docs/api-guide/serializers.md
@@ -457,7 +457,7 @@ To do so, open the Django shell, using `python manage.py shell`, then import the
name = CharField(allow_blank=True, max_length=100, required=False)
owner = PrimaryKeyRelatedField(queryset=User.objects.all())
-## Specifying which fields should be included
+## Specifying which fields to include
If you only want a subset of the default fields to be used in a model serializer, you can do so using `fields` or `exclude` options, just as you would with a `ModelForm`.
@@ -499,7 +499,7 @@ You can add extra fields to a `ModelSerializer` or override the default fields b
Extra fields can correspond to any property or callable on the model.
-## Specifying which fields should be read-only
+## Specifying read only fields
You may wish to specify multiple fields as read-only. Instead of adding each field explicitly with the `read_only=True` attribute, you may use the shortcut Meta option, `read_only_fields`.
@@ -528,7 +528,7 @@ Please review the [Validators Documentation](/api-guide/validators/) for details
---
-## Specifying additional keyword arguments for fields.
+## Additional keyword arguments
There is also a shortcut allowing you to specify arbitrary additional keyword arguments on fields, using the `extra_kwargs` option. Similarly to `read_only_fields` this means you do not need to explicitly declare the field on the serializer.
@@ -567,6 +567,63 @@ The inner `Meta` class on serializers is not inherited from parent classes by de
Typically we would recommend *not* using inheritance on inner Meta classes, but instead declaring all options explicitly.
+## Customizing field mappings
+
+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.
+
+Normally if a `ModelSerializer` does not generate the fields you need by default the you should either add them to the class explicitly, or simply use a regular `Serializer` 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.
+
+### `.serializer_field_mapping`
+
+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.
+
+### `.serializer_relational_field`
+
+This property should be the serializer field class, that is used for relational fields by default. For `ModelSerializer` this defaults to `PrimaryKeyRelatedField`. For `HyperlinkedModelSerializer` this defaults to `HyperlinkedRelatedField`.
+
+### The field_class and field_kwargs API
+
+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 `(field_class, field_kwargs)`.
+
+### `.build_standard_field(self, field_name, model_field)`
+
+Called to generate a serializer field that maps to a standard model field.
+
+The default implementation returns a serializer class based on the `serializer_field_mapping` attribute.
+
+### `.build_relational_field(self, field_name, relation_info)`
+
+Called to generate a serializer field that maps to a relational model field.
+
+The default implementation returns a serializer class based on the `serializer_relational_field` attribute.
+
+The `relation_info` argument is a named tuple, that contains `model_field`, `related_model`, `to_many` and `has_through_model` properties.
+
+### `.build_nested_field(self, field_name, relation_info, nested_depth)`
+
+Called to generate a serializer field that maps to a relational model field, when the `depth` option has been set.
+
+The default implementation dynamically creates a nested serializer class based on either `ModelSerializer` or `HyperlinkedModelSerializer`.
+
+The `nested_depth` will be the value of the `depth` option, minus one.
+
+The `relation_info` argument is a named tuple, that contains `model_field`, `related_model`, `to_many` and `has_through_model` properties.
+
+### `.build_property_field(self, field_name, model_class)`
+
+Called to generate a serializer field that maps to a property or zero-argument method on the model class.
+
+The default implementation returns a `ReadOnlyField` class.
+
+### `.build_url_field(self, field_name, model_class)`
+
+Called to generate a serializer field for the serializer's own `url` field. The default implementation returns a `HyperlinkedIdentityField` class.
+
+### `.build_unknown_field(self, field_name, model_class)`
+
+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.
+
---
# HyperlinkedModelSerializer
diff --git a/docs/api-guide/settings.md b/docs/api-guide/settings.md
index 9005511b..5af429d1 100644
--- a/docs/api-guide/settings.md
+++ b/docs/api-guide/settings.md
@@ -12,10 +12,10 @@ For example your project's `settings.py` file might include something like this:
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': (
- 'rest_framework.renderers.YAMLRenderer',
+ 'rest_framework.renderers.JSONRenderer',
),
'DEFAULT_PARSER_CLASSES': (
- 'rest_framework.parsers.YAMLParser',
+ 'rest_framework.parsers.JSONParser',
)
}
@@ -166,6 +166,28 @@ Default: `ordering`
---
+## Versioning settings
+
+#### DEFAULT_VERSION
+
+The value that should be used for `request.version` when no versioning information is present.
+
+Default: `None`
+
+#### ALLOWED_VERSIONS
+
+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.
+
+Default: `None`
+
+#### VERSION_PARAMETER
+
+The string that should used for any versioning parameters, such as in the media type or URL query parameters.
+
+Default: `'version'`
+
+---
+
## Authentication settings
*The following settings control the behavior of unauthenticated requests.*
@@ -393,7 +415,7 @@ This setting can be changed to support error responses other than the default `{
This should be a function with the following signature:
- exception_handler(exc)
+ exception_handler(exc, context)
* `exc`: The exception.
diff --git a/docs/api-guide/testing.md b/docs/api-guide/testing.md
index d059fdab..cd8c7820 100644
--- a/docs/api-guide/testing.md
+++ b/docs/api-guide/testing.md
@@ -255,14 +255,14 @@ The default format used to make test requests may be set using the `TEST_REQUEST
If you need to test requests using something other than multipart or json requests, you can do so by setting the `TEST_REQUEST_RENDERER_CLASSES` setting.
-For example, to add support for using `format='yaml'` in test requests, you might have something like this in your `settings.py` file.
+For example, to add support for using `format='html'` in test requests, you might have something like this in your `settings.py` file.
REST_FRAMEWORK = {
...
'TEST_REQUEST_RENDERER_CLASSES': (
'rest_framework.renderers.MultiPartRenderer',
'rest_framework.renderers.JSONRenderer',
- 'rest_framework.renderers.YAMLRenderer'
+ 'rest_framework.renderers.TemplateHTMLRenderer'
)
}
diff --git a/docs/api-guide/versioning.md b/docs/api-guide/versioning.md
new file mode 100644
index 00000000..92380cc0
--- /dev/null
+++ b/docs/api-guide/versioning.md
@@ -0,0 +1,202 @@
+source: versioning.py
+
+# Versioning
+
+> Versioning an interface is just a "polite" way to kill deployed clients.
+>
+> &mdash; [Roy Fielding][cite].
+
+API versioning allows you to alter behavior between different clients. REST framework provides for a number of different versioning schemes.
+
+Versioning is determined by the incoming client request, and may either be based on the request URL, or based on the request headers.
+
+## Versioning with REST framework
+
+When API versioning is enabled, the `request.version` attribute will contain a string that corresponds to the version requested in the incoming client request.
+
+By default, versioning is not enabled, and `request.version` will always return `None`.
+
+#### Varying behavior based on the version
+
+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:
+
+ def get_serializer_class(self):
+ if self.request.version == 'v1':
+ return AccountSerializerVersion1
+ return AccountSerializer
+
+#### Reversing URLs for versioned APIs
+
+The `reverse` function included by REST framework ties in with the versioning scheme. You need to make sure to include the current `request` as a keyword argument, like so.
+
+ reverse('bookings-list', request=request)
+
+The above function will apply any URL transformations appropriate to the request version. For example:
+
+* If `NamespacedVersioning` was being used, and the API version was 'v1', then the URL lookup used would be `'v1:bookings-list'`, which might resolve to a URL like `http://example.org/v1/bookings/`.
+* If `QueryParameterVersioning` was being used, and the API version was `1.0`, then the returned URL might be something like `http://example.org/bookings/?version=1.0`
+
+#### Versioned APIs and hyperlinked serializers
+
+When using hyperlinked serialization styles together with a URL based versioning scheme make sure to include the request as context to the serializer.
+
+ def get(self, request):
+ queryset = Booking.objects.all()
+ serializer = BookingsSerializer(queryset, many=True, context={'request': request})
+ return Response({'all_bookings': serializer.data})
+
+Doing so will allow any returned URLs to include the appropriate versioning.
+
+## Configuring the versioning scheme
+
+The versioning scheme is defined by the `DEFAULT_VERSIONING_CLASS` settings key.
+
+ REST_FRAMEWORK = {
+ 'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.NamespaceVersioning'
+ }
+
+Unless it is explicitly set, the value for `DEFAULT_VERSIONING_CLASS` will be `None`. In this case the `request.version` attribute will always return `None`.
+
+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 `versioning_class` attribute.
+
+ class ProfileList(APIView):
+ versioning_class = versioning.QueryParameterVersioning
+
+#### Other versioning settings
+
+The following settings keys are also used to control versioning:
+
+* `DEFAULT_VERSION`. The value that should be used for `request.version` when no versioning information is present. Defaults to `None`.
+* `ALLOWED_VERSIONS`. 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 `None`.
+* `VERSION_PARAMETER`. The string that should used for any versioning parameters, such as in the media type or URL query parameters. Defaults to `'version'`.
+
+---
+
+# API Reference
+
+## AcceptHeaderVersioning
+
+This scheme requires the client to specify the version as part of the media type in the `Accept` header. The version is included as a media type parameter, that supplements the main media type.
+
+Here's an example HTTP request using the accept header versioning style.
+
+ GET /bookings/ HTTP/1.1
+ Host: example.com
+ Accept: application/json; version=1.0
+
+In the example request above `request.version` attribute would return the string `'1.0'`.
+
+Versioning based on accept headers is [generally considered][klabnik-guidelines] as [best practice][heroku-guidelines], although other styles may be suitable depending on your client requirements.
+
+#### Using accept headers with vendor media types
+
+Strictly speaking the `json` media type is not specified as [including additional parameters][json-parameters]. If you are building a well-specified public API you might consider using a [vendor media type][vendor-media-type]. To do so, configure your renderers to use a JSON based renderer with a custom media type:
+
+ class BookingsAPIRenderer(JSONRenderer):
+ media_type = 'application/vnd.megacorp.bookings+json'
+
+Your client requests would now look like this:
+
+ GET /bookings/ HTTP/1.1
+ Host: example.com
+ Accept: application/vnd.megacorp.bookings+json; version=1.0
+
+## URLParameterVersioning
+
+This scheme requires the client to specify the version as part of the URL path.
+
+ GET /v1/bookings/ HTTP/1.1
+ Host: example.com
+ Accept: application/json
+
+Your URL conf must include a pattern that matches the version with a `'version'` keyword argument, so that this information is available to the versioning scheme.
+
+ urlpatterns = [
+ url(
+ r'^(?P<version>{v1,v2})/bookings/$',
+ bookings_list,
+ name='bookings-list'
+ ),
+ url(
+ r'^(?P<version>{v1,v2})/bookings/(?P<pk>[0-9]+)/$',
+ bookings_detail,
+ name='bookings-detail'
+ )
+ ]
+
+## NamespaceVersioning
+
+To the client, this scheme is the same as `URLParameterVersioning`. The only difference is how it is configured in your Django application, as it uses URL namespacing, instead of URL keyword arguments.
+
+ GET /v1/something/ HTTP/1.1
+ Host: example.com
+ Accept: application/json
+
+With this scheme the `request.version` attribute is determined based on the `namespace` that matches the incoming request path.
+
+In the following example we're giving a set of views two different possible URL prefixes, each under a different namespace:
+
+ # bookings/urls.py
+ urlpatterns = [
+ url(r'^$', bookings_list, name='bookings-list'),
+ url(r'^(?P<pk>[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'))
+ ]
+
+Both `URLParameterVersioning` and `NamespaceVersioning` are reasonable if you just need a simple versioning scheme. The `URLParameterVersioning` approach might be better suitable for small ad-hoc projects, and the `NaemspaceVersioning` is probably easier to manage for larger projects.
+
+## HostNameVersioning
+
+The hostname versioning scheme requires the client to specify the requested version as part of the hostname in the URL.
+
+For example the following is an HTTP request to the `http://v1.example.com/bookings/` URL:
+
+ GET /bookings/ HTTP/1.1
+ Host: v1.example.com
+ Accept: application/json
+
+By default this implementation expects the hostname to match this simple regular expression:
+
+ ^([a-zA-Z0-9]+)\.[a-zA-Z0-9]+\.[a-zA-Z0-9]+$
+
+Note that the first group is enclosed in brackets, indicating that this is the matched portion of the hostname.
+
+The `HostNameVersioning` scheme can be awkward to use in debug mode as you will typically be accessing a raw IP address such as `127.0.0.1`. There are various online services which you to [access localhost with a custom subdomain][lvh] which you may find helpful in this case.
+
+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.
+
+## QueryParameterVersioning
+
+This scheme is a simple style that includes the version as a query parameter in the URL. For example:
+
+ GET /something/?version=0.1 HTTP/1.1
+ Host: example.com
+ Accept: application/json
+
+---
+
+# Custom versioning schemes
+
+To implement a custom versioning scheme, subclass `BaseVersioning` and override the `.determine_version` method.
+
+## Example
+
+The following example uses a custom `X-API-Version` header to determine the requested version.
+
+ class XAPIVersionScheme(versioning.BaseVersioning):
+ def determine_version(self, request, *args, **kwargs):
+ return request.META.get('HTTP_X_API_VERSION', None)
+
+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 `.reverse()` method on the class. See the source code for examples.
+
+[cite]: http://www.slideshare.net/evolve_conference/201308-fielding-evolve/31
+[klabnik-guidelines]: http://blog.steveklabnik.com/posts/2011-07-03-nobody-understands-rest-or-http#i_want_my_api_to_be_versioned
+[heroku-guidelines]: https://github.com/interagent/http-api-design#version-with-accepts-header
+[json-parameters]: http://tools.ietf.org/html/rfc4627#section-6
+[vendor-media-type]: http://en.wikipedia.org/wiki/Internet_media_type#Vendor_tree
+[lvh]: https://reinteractive.net/posts/199-developing-and-testing-rails-applications-with-subdomains
diff --git a/docs/index.md b/docs/index.md
index 55129df1..7ccec12f 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -34,7 +34,7 @@ Django REST framework is a powerful and flexible toolkit that makes it easy to b
Some reasons you might want to use REST framework:
* The [Web browsable API][sandbox] is a huge usability win for your developers.
-* [Authentication policies][authentication] including [OAuth1a][oauth1-section] and [OAuth2][oauth2-section] out of the box.
+* [Authentication policies][authentication] including optional packages for [OAuth1a][oauth1-section] and [OAuth2][oauth2-section].
* [Serialization][serializers] that supports both [ORM][modelserializer-section] and [non-ORM][serializer-section] data sources.
* Customizable all the way down - just use [regular function-based views][functionview-section] if you don't need the [more][generic-views] [powerful][viewsets] [features][routers].
* [Extensive documentation][index], and [great community support][group].
@@ -56,15 +56,10 @@ REST framework requires the following:
The following packages are optional:
* [Markdown][markdown] (2.1.0+) - Markdown support for the browsable API.
-* [PyYAML][yaml] (3.10+) - YAML content-type support.
-* [defusedxml][defusedxml] (0.3+) - XML content-type support.
* [django-filter][django-filter] (0.5.4+) - Filtering support.
-* [django-oauth-plus][django-oauth-plus] (2.0+) and [oauth2][oauth2] (1.5.211+) - OAuth 1.0a support.
-* [django-oauth2-provider][django-oauth2-provider] (0.2.3+) - OAuth 2.0 support.
+* [django-restframework-oauth][django-restframework-oauth] package for OAuth 1.0a and 2.0 support.
* [django-guardian][django-guardian] (1.1.1+) - Object level permissions support.
-**Note**: The `oauth2` Python package is badly misnamed, and actually provides OAuth 1.0a support. Also note that packages required for both OAuth 1.0a, and OAuth 2.0 are not yet Python 3 compatible.
-
## Installation
Install using `pip`, including any optional packages you want...
@@ -180,6 +175,7 @@ The API guide is your complete reference manual to all the functionality provide
* [Throttling][throttling]
* [Filtering][filtering]
* [Pagination][pagination]
+* [Versioning][versioning]
* [Content negotiation][contentnegotiation]
* [Metadata][metadata]
* [Format suffixes][formatsuffixes]
@@ -263,12 +259,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[mozilla]: http://www.mozilla.org/en-US/about/
[eventbrite]: https://www.eventbrite.co.uk/about/
[markdown]: http://pypi.python.org/pypi/Markdown/
-[yaml]: http://pypi.python.org/pypi/PyYAML
-[defusedxml]: https://pypi.python.org/pypi/defusedxml
[django-filter]: http://pypi.python.org/pypi/django-filter
-[oauth2]: https://github.com/simplegeo/python-oauth2
-[django-oauth-plus]: https://bitbucket.org/david/django-oauth-plus/wiki/Home
-[django-oauth2-provider]: https://github.com/caffeinehit/django-oauth2-provider
+[django-restframework-oauth]: https://github.com/jlafon/django-rest-framework-oauth
[django-guardian]: https://github.com/lukaszb/django-guardian
[0.4]: https://github.com/tomchristie/django-rest-framework/tree/0.4.X
[image]: img/quickstart.png
@@ -305,6 +297,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
[throttling]: api-guide/throttling.md
[filtering]: api-guide/filtering.md
[pagination]: api-guide/pagination.md
+[versioning]: api-guide/versioning.md
[contentnegotiation]: api-guide/content-negotiation.md
[metadata]: api-guide/metadata.md
[formatsuffixes]: api-guide/format-suffixes.md
diff --git a/docs/tutorial/2-requests-and-responses.md b/docs/tutorial/2-requests-and-responses.md
index c0426969..4ca4e264 100644
--- a/docs/tutorial/2-requests-and-responses.md
+++ b/docs/tutorial/2-requests-and-responses.md
@@ -92,7 +92,7 @@ Here is the view for an individual snippet, in the `views.py` module.
This should all feel very familiar - it is not a lot different from working with regular Django views.
-Notice that we're no longer explicitly tying our requests or responses to a given content type. `request.data` can handle incoming `json` requests, but it can also handle `yaml` and other formats. Similarly we're returning response objects with data, but allowing REST framework to render the response into the correct content type for us.
+Notice that we're no longer explicitly tying our requests or responses to a given content type. `request.data` can handle incoming `json` requests, but it can also handle other formats. Similarly we're returning response objects with data, but allowing REST framework to render the response into the correct content type for us.
## Adding optional format suffixes to our URLs