Note that you'll want to ensure you place this code snippet in an installed `models.py` module, or some other location that will be imported by Django on startup.
If you've already created some users, you can generate tokens for all existing users like this:
If you've already created some users, you can generate tokens for all existing users like this:
from django.contrib.auth.models import User
from django.contrib.auth.models import User
...
@@ -336,6 +346,10 @@ If the `.authenticate_header()` method is not overridden, the authentication sch
...
@@ -336,6 +346,10 @@ If the `.authenticate_header()` method is not overridden, the authentication sch
The following example will authenticate any incoming request as the user given by the username in a custom request header named 'X_USERNAME'.
The following example will authenticate any incoming request as the user given by the username in a custom request header named 'X_USERNAME'.
from django.contrib.auth.models import User
from rest_framework import authentication
from rest_framework import exceptions
class ExampleAuthentication(authentication.BaseAuthentication):
class ExampleAuthentication(authentication.BaseAuthentication):
def authenticate(self, request):
def authenticate(self, request):
username = request.META.get('X_USERNAME')
username = request.META.get('X_USERNAME')
...
@@ -390,4 +404,4 @@ The [Django OAuth2 Consumer][doac] library from [Rediker Software][rediker] is a
...
@@ -390,4 +404,4 @@ The [Django OAuth2 Consumer][doac] library from [Rediker Software][rediker] is a
@@ -28,11 +28,54 @@ For example, the following request:
...
@@ -28,11 +28,54 @@ For example, the following request:
Might receive an error response indicating that the `DELETE` method is not allowed on that resource:
Might receive an error response indicating that the `DELETE` method is not allowed on that resource:
HTTP/1.1 405 Method Not Allowed
HTTP/1.1 405 Method Not Allowed
Content-Type: application/json; charset=utf-8
Content-Type: application/json
Content-Length: 42
Content-Length: 42
{"detail": "Method 'DELETE' not allowed."}
{"detail": "Method 'DELETE' not allowed."}
## Custom exception handling
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.
The function must take a single argument, which is the exception to be handled, and should either return a `Response` object, or return `None` if the exception cannot be handled. If the handler returns `None` then the exception will be re-raised and Django will return a standard HTTP 500 'server error' response.
For example, you might want to ensure that all error responses include the HTTP status code in the body of the response, like so:
HTTP/1.1 405 Method Not Allowed
Content-Type: application/json
Content-Length: 62
{"status_code": 405, "detail": "Method 'DELETE' not allowed."}
In order to alter the style of the response, you could write the following custom exception handler:
from rest_framework.views import exception_handler
Note that the exception handler will only be called for responses generated by raised exceptions. It will not be used for any responses returned directly by the view, such as the `HTTP_400_BAD_REQUEST` responses that are returned by the generic views when serializer validation fails.
@@ -78,6 +78,9 @@ A generic, **read-only** field. You can use this field for any attribute that d
...
@@ -78,6 +78,9 @@ A generic, **read-only** field. You can use this field for any attribute that d
For example, using the following model.
For example, using the following model.
from django.db import models
from django.utils.timezone import now
class Account(models.Model):
class Account(models.Model):
owner = models.ForeignKey('auth.user')
owner = models.ForeignKey('auth.user')
name = models.CharField(max_length=100)
name = models.CharField(max_length=100)
...
@@ -85,13 +88,14 @@ For example, using the following model.
...
@@ -85,13 +88,14 @@ For example, using the following model.
payment_expiry = models.DateTimeField()
payment_expiry = models.DateTimeField()
def has_expired(self):
def has_expired(self):
now = datetime.datetime.now()
return now() > self.payment_expiry
return now > self.payment_expiry
A serializer definition that looked like this:
A serializer definition that looked like this:
from rest_framework import serializers
class AccountSerializer(serializers.HyperlinkedModelSerializer):
class AccountSerializer(serializers.HyperlinkedModelSerializer):
expired = Field(source='has_expired')
expired = serializers.Field(source='has_expired')
class Meta:
class Meta:
fields = ('url', 'owner', 'name', 'expired')
fields = ('url', 'owner', 'name', 'expired')
...
@@ -125,12 +129,11 @@ The `ModelField` class is generally intended for internal use, but can be used b
...
@@ -125,12 +129,11 @@ The `ModelField` class is generally intended for internal use, but can be used b
This is a read-only field. It gets its value by calling a method on the serializer class it is attached to. It can be used to add any sort of data to the serialized representation of your object. The field's constructor accepts a single argument, which is the name of the method on the serializer to be called. The method should accept a single argument (in addition to `self`), which is the object being serialized. It should return whatever you want to be included in the serialized representation of the object. For example:
This is a read-only field. It gets its value by calling a method on the serializer class it is attached to. It can be used to add any sort of data to the serialized representation of your object. The field's constructor accepts a single argument, which is the name of the method on the serializer to be called. The method should accept a single argument (in addition to `self`), which is the object being serialized. It should return whatever you want to be included in the serialized representation of the object. For example:
from rest_framework import serializers
from django.contrib.auth.models import User
from django.contrib.auth.models import User
from django.utils.timezone import now
from django.utils.timezone import now
from rest_framework import serializers
class UserSerializer(serializers.ModelSerializer):
class UserSerializer(serializers.ModelSerializer):
@@ -17,6 +17,11 @@ If the generic views don't suit the needs of your API, you can drop down to usin
...
@@ -17,6 +17,11 @@ If the generic views don't suit the needs of your API, you can drop down to usin
Typically when using the generic views, you'll override the view, and set several class attributes.
Typically when using the generic views, you'll override the view, and set several class attributes.
from django.contrib.auth.models import User
from myapp.serializers import UserSerializer
from rest_framework import generics
from rest_framework.permissions import IsAdminUser
class UserList(generics.ListCreateAPIView):
class UserList(generics.ListCreateAPIView):
queryset = User.objects.all()
queryset = User.objects.all()
serializer_class = UserSerializer
serializer_class = UserSerializer
...
@@ -68,7 +73,7 @@ The following attributes control the basic view behavior.
...
@@ -68,7 +73,7 @@ The following attributes control the basic view behavior.
**Pagination**:
**Pagination**:
The following attibutes are used to control pagination when used with list views.
The following attributes are used to control pagination when used with list views.
*`paginate_by` - The size of pages to use with paginated data. If set to `None` then pagination is turned off. If unset this uses the same value as the `PAGINATE_BY` setting, which defaults to `None`.
*`paginate_by` - The size of pages to use with paginated data. If set to `None` then pagination is turned off. If unset this uses the same value as the `PAGINATE_BY` setting, which defaults to `None`.
*`paginate_by_param` - 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 `PAGINATE_BY_PARAM` setting, which defaults to `None`.
*`paginate_by_param` - 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 `PAGINATE_BY_PARAM` setting, which defaults to `None`.
...
@@ -108,7 +113,12 @@ For example:
...
@@ -108,7 +113,12 @@ For example:
filter = {}
filter = {}
for field in self.multiple_lookup_fields:
for field in self.multiple_lookup_fields:
filter[field] = self.kwargs[field]
filter[field] = self.kwargs[field]
return get_object_or_404(queryset, **filter)
obj = get_object_or_404(queryset, **filter)
self.check_object_permissions(self.request, obj)
return obj
Note that if your API doesn't include any object level permissions, you may optionally exclude the ``self.check_object_permissions, and simply return the object from the `get_object_or_404` lookup.
#### `get_serializer_class(self)`
#### `get_serializer_class(self)`
...
@@ -125,7 +135,7 @@ For example:
...
@@ -125,7 +135,7 @@ For example:
#### `get_paginate_by(self)`
#### `get_paginate_by(self)`
Returns the page size to use with pagination. By default this uses the `paginate_by` attribute, and may be overridden by the cient if the `paginate_by_param` attribute is set.
Returns the page size to use with pagination. By default this uses the `paginate_by` attribute, and may be overridden by the client if the `paginate_by_param` attribute is set.
You may want to override this method to provide more complex behavior such as modifying page sizes based on the media type of the response.
You may want to override this method to provide more complex behavior such as modifying page sizes based on the media type of the response.
@@ -13,6 +13,7 @@ REST framework includes a `PaginationSerializer` class that makes it easy to ret
...
@@ -13,6 +13,7 @@ REST framework includes a `PaginationSerializer` class that makes it easy to ret
Let's start by taking a look at an example from the Django documentation.
Let's start by taking a look at an example from the Django documentation.
from django.core.paginator import Paginator
from django.core.paginator import Paginator
objects = ['john', 'paul', 'george', 'ringo']
objects = ['john', 'paul', 'george', 'ringo']
paginator = Paginator(objects, 2)
paginator = Paginator(objects, 2)
page = paginator.page(1)
page = paginator.page(1)
...
@@ -22,6 +23,7 @@ Let's start by taking a look at an example from the Django documentation.
...
@@ -22,6 +23,7 @@ Let's start by taking a look at an example from the Django documentation.
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.
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.
from rest_framework.pagination import PaginationSerializer
from rest_framework.pagination import PaginationSerializer
@@ -83,11 +85,12 @@ We could now use our pagination serializer in a view like this.
...
@@ -83,11 +85,12 @@ We could now use our pagination serializer in a view like this.
The generic class based views `ListAPIView` and `ListCreateAPIView` 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.
The generic class based views `ListAPIView` and `ListCreateAPIView` 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.
The default pagination style may be set globally, using the `DEFAULT_PAGINATION_SERIALIZER_CLASS`, `PAGINATE_BY` and `PAGINATE_BY_PARAM` settings. For example.
The default pagination style may be set globally, using the `DEFAULT_PAGINATION_SERIALIZER_CLASS`, `PAGINATE_BY`, `PAGINATE_BY_PARAM`, and `MAX_PAGINATE_BY` settings. For example.
REST_FRAMEWORK = {
REST_FRAMEWORK = {
'PAGINATE_BY': 10,
'PAGINATE_BY': 10, # Default to 10
'PAGINATE_BY_PARAM': 'page_size'
'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`.
}
}
You can also set the pagination style on a per-view basis, using the `ListAPIView` generic class-based view.
You can also set the pagination style on a per-view basis, using the `ListAPIView` generic class-based view.
...
@@ -97,6 +100,7 @@ You can also set the pagination style on a per-view basis, using the `ListAPIVie
...
@@ -97,6 +100,7 @@ You can also set the pagination style on a per-view basis, using the `ListAPIVie
serializer_class = ExampleModelSerializer
serializer_class = ExampleModelSerializer
paginate_by = 10
paginate_by = 10
paginate_by_param = 'page_size'
paginate_by_param = 'page_size'
max_paginate_by = 100
Note that using a `paginate_by` value of `None` will turn off pagination for the view.
Note that using a `paginate_by` value of `None` will turn off pagination for the view.
...
@@ -114,6 +118,9 @@ You can also override the name used for the object list field, by setting the `r
...
@@ -114,6 +118,9 @@ You can also override the name used for the object list field, by setting the `r
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.
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.
from rest_framework import pagination
from rest_framework import serializers
class LinksSerializer(serializers.Serializer):
class LinksSerializer(serializers.Serializer):
next = pagination.NextPageField(source='*')
next = pagination.NextPageField(source='*')
prev = pagination.PreviousPageField(source='*')
prev = pagination.PreviousPageField(source='*')
...
@@ -135,7 +142,7 @@ To have your custom pagination serializer be used by default, use the `DEFAULT_P
...
@@ -135,7 +142,7 @@ To have your custom pagination serializer be used by default, use the `DEFAULT_P
Alternatively, to set your custom pagination serializer on a per-view basis, use the `pagination_serializer_class` attribute on a generic class based view:
Alternatively, to set your custom pagination serializer on a per-view basis, use the `pagination_serializer_class` attribute on a generic class based view:
@@ -25,9 +25,17 @@ Object level permissions are run by REST framework's generic views when `.get_ob
...
@@ -25,9 +25,17 @@ Object level permissions are run by REST framework's generic views when `.get_ob
As with view level permissions, an `exceptions.PermissionDenied` exception will be raised if the user is not allowed to act on the given object.
As with view level permissions, an `exceptions.PermissionDenied` exception will be raised if the user is not allowed to act on the given object.
If you're writing your own views and want to enforce object level permissions,
If you're writing your own views and want to enforce object level permissions,
you'll need to explicitly call the `.check_object_permissions(request, obj)` method on the view at the point at which you've retrieved the object.
or if you override the `get_object` method on a generic view, then you'll need to explicitly call the `.check_object_permissions(request, obj)` method on the view at the point at which you've retrieved the object.
This will either raise a `PermissionDenied` or `NotAuthenticated` exception, or simply return if the view has the appropriate permissions.
This will either raise a `PermissionDenied` or `NotAuthenticated` exception, or simply return if the view has the appropriate permissions.
For example:
def get_object(self):
obj = get_object_or_404(self.get_queryset())
self.check_object_permissions(self.request, obj)
return obj
## Setting the permission policy
## Setting the permission policy
The default permission policy may be set globally, using the `DEFAULT_PERMISSION_CLASSES` setting. For example.
The default permission policy may be set globally, using the `DEFAULT_PERMISSION_CLASSES` setting. For example.
...
@@ -47,6 +55,10 @@ If not specified, this setting defaults to allowing unrestricted access:
...
@@ -47,6 +55,10 @@ If not specified, this setting defaults to allowing unrestricted access:
You can also set the authentication policy on a per-view, or per-viewset basis,
You can also set the authentication policy on a per-view, or per-viewset basis,
using the `APIView` class based views.
using the `APIView` class based views.
from rest_framework.permissions import IsAuthenticated
from rest_framework.responses import Response
from rest_framework.views import APIView
class ExampleView(APIView):
class ExampleView(APIView):
permission_classes = (IsAuthenticated,)
permission_classes = (IsAuthenticated,)
...
@@ -157,6 +169,8 @@ For more details see the [2.2 release announcement][2.2-announcement].
...
@@ -157,6 +169,8 @@ For more details see the [2.2 release announcement][2.2-announcement].
The following is an example of a permission class that checks the incoming request's IP address against a blacklist, and denies the request if the IP has been blacklisted.
The following is an example of a permission class that checks the incoming request's IP address against a blacklist, and denies the request if the IP has been blacklisted.
from rest_framework import permissions
class BlacklistPermission(permissions.BasePermission):
class BlacklistPermission(permissions.BasePermission):
"""
"""
Global permission check for blacklisted IPs.
Global permission check for blacklisted IPs.
...
@@ -198,6 +212,10 @@ The following third party packages are also available.
...
@@ -198,6 +212,10 @@ The following third party packages are also available.
The [DRF Any Permissions][drf-any-permissions] packages provides a different permission behavior in contrast to REST framework. Instead of all specified permissions being required, only one of the given permissions has to be true in order to get access to the view.
The [DRF Any Permissions][drf-any-permissions] packages provides a different permission behavior in contrast to REST framework. Instead of all specified permissions being required, only one of the given permissions has to be true in order to get access to the view.
## Composed Permissions
The [Composed Permissions][composed-permissions] package provides a simple way to define complex and multi-depth (with logic operators) permission objects, using small and reusable components.
@@ -183,7 +184,7 @@ When using `SlugRelatedField` as a read-write field, you will normally want to e
...
@@ -183,7 +184,7 @@ When using `SlugRelatedField` as a read-write field, you will normally want to e
This field can be applied as an identity relationship, such as the `'url'` field on a HyperlinkedModelSerializer. It can also be used for an attribute on the object. For example, the following serializer:
This field can be applied as an identity relationship, such as the `'url'` field on a HyperlinkedModelSerializer. It can also be used for an attribute on the object. For example, the following serializer:
class AlbumSerializer(serializers.HyperlinkedModelSerializer):
class AlbumSerializer(serializers.HyperlinkedModelSerializer):
@@ -83,7 +88,7 @@ The client may additionally include an `'indent'` media type parameter, in which
...
@@ -83,7 +88,7 @@ The client may additionally include an `'indent'` media type parameter, in which
**.format**: `'.json'`
**.format**: `'.json'`
**.charset**: `utf-8`
**.charset**: `None`
## UnicodeJSONRenderer
## UnicodeJSONRenderer
...
@@ -105,7 +110,7 @@ Both the `JSONRenderer` and `UnicodeJSONRenderer` styles conform to [RFC 4627][r
...
@@ -105,7 +110,7 @@ Both the `JSONRenderer` and `UnicodeJSONRenderer` styles conform to [RFC 4627][r
**.format**: `'.json'`
**.format**: `'.json'`
**.charset**: `utf-8`
**.charset**: `None`
## JSONPRenderer
## JSONPRenderer
...
@@ -207,6 +212,20 @@ You can use `TemplateHTMLRenderer` either to return regular HTML pages using RES
...
@@ -207,6 +212,20 @@ You can use `TemplateHTMLRenderer` either to return regular HTML pages using RES
See also: `TemplateHTMLRenderer`
See also: `TemplateHTMLRenderer`
## HTMLFormRenderer
Renders data returned by a serializer into an HTML form. The output of this renderer does not include the enclosing `<form>` tags or an submit actions, as you'll probably need those to include the desired method and URL. Also note that the `HTMLFormRenderer` does not yet support including field error messages.
Note that the template used by the `HTMLFormRenderer` class, and the context submitted to it **may be subject to change**. If you need to use this renderer class it is advised that you either make a local copy of the class and templates, or follow the release note on REST framework upgrades closely.
**.media_type**: `text/html`
**.format**: `'.form'`
**.charset**: `utf-8`
**.template**: `'rest_framework/form.html'`
## BrowsableAPIRenderer
## BrowsableAPIRenderer
Renders data into HTML for the Browsable API. This renderer will determine which other renderer would have been given highest priority, and use that to display an API style response within the HTML page.
Renders data into HTML for the Browsable API. This renderer will determine which other renderer would have been given highest priority, and use that to display an API style response within the HTML page.
...
@@ -217,6 +236,8 @@ Renders data into HTML for the Browsable API. This renderer will determine whic
...
@@ -217,6 +236,8 @@ Renders data into HTML for the Browsable API. This renderer will determine whic
**.charset**: `utf-8`
**.charset**: `utf-8`
**.template**: `'rest_framework/api.html'`
#### Customizing BrowsableAPIRenderer
#### Customizing BrowsableAPIRenderer
By default the response content will be rendered with the highest priority renderer apart from `BrowseableAPIRenderer`. If you need to customize this behavior, for example to use HTML as the default return format, but use JSON in the browsable API, you can do so by overriding the `get_default_renderer()` method. For example:
By default the response content will be rendered with the highest priority renderer apart from `BrowseableAPIRenderer`. If you need to customize this behavior, for example to use HTML as the default return format, but use JSON in the browsable API, you can do so by overriding the `get_default_renderer()` method. For example:
...
@@ -290,12 +311,15 @@ By default renderer classes are assumed to be using the `UTF-8` encoding. To us
...
@@ -290,12 +311,15 @@ By default renderer classes are assumed to be using the `UTF-8` encoding. To us
Note that if a renderer class returns a unicode string, then the response content will be coerced into a bytestring by the `Response` class, with the `charset` attribute set on the renderer used to determine the encoding.
Note that if a renderer class returns a unicode string, then the response content will be coerced into a bytestring by the `Response` class, with the `charset` attribute set on the renderer used to determine the encoding.
If the renderer returns a bytestring representing raw binary content, you should set a charset value of `None`, which will ensure the `Content-Type` header of the response will not have a `charset` value set. Doing so will also ensure that the browsable API will not attempt to display the binary content as a string.
If the renderer returns a bytestring representing raw binary content, you should set a charset value of `None`, which will ensure the `Content-Type` header of the response will not have a `charset` value set.
In some cases you may also want to set the `render_style` attribute to `'binary'`. Doing so will also ensure that the browsable API will not attempt to display the binary content as a string.
@@ -117,7 +117,7 @@ For more information see the [browser enhancements documentation].
...
@@ -117,7 +117,7 @@ For more information see the [browser enhancements documentation].
# Standard HttpRequest attributes
# Standard HttpRequest attributes
As REST framework's `Request` extends Django's `HttpRequest`, all the other standard attributes and methods are also available. For example the `request.META`dictionary is available as normal.
As REST framework's `Request` extends Django's `HttpRequest`, all the other standard attributes and methods are also available. For example the `request.META`and `request.session` dictionaries are available as normal.
Note that due to implementation reasons the `Request` class does not inherit from `HttpRequest` class, but instead extends the class using composition.
Note that due to implementation reasons the `Request` class does not inherit from `HttpRequest` class, but instead extends the class using composition.
@@ -67,6 +71,9 @@ At this point we've translated the model instance into Python native datatypes.
...
@@ -67,6 +71,9 @@ At this point we've translated the model instance into Python native datatypes.
Deserialization is similar. First we parse a stream into Python native datatypes...
Deserialization is similar. First we parse a stream into Python native datatypes...
from StringIO import StringIO
from rest_framework.parsers import JSONParser
stream = StringIO(json)
stream = StringIO(json)
data = JSONParser().parse(stream)
data = JSONParser().parse(stream)
...
@@ -177,7 +184,7 @@ If a nested representation may optionally accept the `None` value you should pas
...
@@ -177,7 +184,7 @@ If a nested representation may optionally accept the `None` value you should pas
content = serializers.CharField(max_length=200)
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
created = serializers.DateTimeField()
Similarly if a nested representation should be a list of items, you should the `many=True` flag to the nested serialized.
Similarly if a nested representation should be a list of items, you should pass the `many=True` flag to the nested serialized.
class CommentSerializer(serializers.Serializer):
class CommentSerializer(serializers.Serializer):
user = UserSerializer(required=False)
user = UserSerializer(required=False)
...
@@ -185,11 +192,13 @@ Similarly if a nested representation should be a list of items, you should the `
...
@@ -185,11 +192,13 @@ Similarly if a nested representation should be a list of items, you should the `
content = serializers.CharField(max_length=200)
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
created = serializers.DateTimeField()
---
Validation of nested objects will work the same as before. Errors with nested objects will be nested under the field name of the nested object.
**Note**:Nested serializers are only suitable for read-only representations, as there are cases where they would have ambiguous or non-obvious behavior if used when updating instances. For read-write representations you should always use a flat representation, by using one of the `RelatedField` subclasses.
serialize.save() # `.save()` will be called on each updated or newly created instance.
serializer.save() # `.save()` will be called on each updated or newly created instance.
By default bulk updates will be limited to updating instances that already exist in the provided queryset.
By default bulk updates will be limited to updating instances that already exist in the provided queryset.
...
@@ -253,7 +262,7 @@ When performing a bulk update you may want to allow new items to be created, and
...
@@ -253,7 +262,7 @@ When performing a bulk update you may want to allow new items to be created, and
serializer.save() # `.save()` will be called on updated or newly created instances.
serializer.save() # `.save()` will be called on updated or newly created instances.
# `.delete()` will be called on any other items in the `queryset`.
# `.delete()` will be called on any other items in the `queryset`.
Passing `allow_add_remove=True` ensures that any update operations will completely overwrite the existing queryset, rather than simply updating existing objects.
Passing `allow_add_remove=True` ensures that any update operations will completely overwrite the existing queryset, rather than simply updating existing objects.
#### How identity is determined when performing bulk updates
#### How identity is determined when performing bulk updates
...
@@ -293,8 +302,7 @@ You can provide arbitrary additional context by passing a `context` argument whe
...
@@ -293,8 +302,7 @@ You can provide arbitrary additional context by passing a `context` argument whe
The context dictionary can be used within any serializer field logic, such as a custom `.to_native()` method, by accessing the `self.context` attribute.
The context dictionary can be used within any serializer field logic, such as a custom `.to_native()` method, by accessing the `self.context` attribute.
---
-
# ModelSerializer
# ModelSerializer
Often you'll want serializer classes that map closely to model definitions.
Often you'll want serializer classes that map closely to model definitions.
...
@@ -337,6 +345,8 @@ The default `ModelSerializer` uses primary keys for relationships, but you can a
...
@@ -337,6 +345,8 @@ The default `ModelSerializer` uses primary keys for relationships, but you can a
The `depth` option should be set to an integer value that indicates the depth of relationships that should be traversed before reverting to a flat representation.
The `depth` option should be set to an integer value that indicates the depth of relationships that should be traversed before reverting to a flat representation.
If you want to customize the way the serialization is done (e.g. using `allow_add_remove`) you'll need to define the field yourself.
## Specifying which fields should be read-only
## Specifying which fields should be read-only
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 `read_only_fields` Meta option, like so:
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 `read_only_fields` Meta option, like so:
@@ -25,7 +25,7 @@ If you need to access the values of REST framework's API settings in your projec
...
@@ -25,7 +25,7 @@ If you need to access the values of REST framework's API settings in your projec
you should use the `api_settings` object. For example.
you should use the `api_settings` object. For example.
from rest_framework.settings import api_settings
from rest_framework.settings import api_settings
print api_settings.DEFAULT_AUTHENTICATION_CLASSES
print api_settings.DEFAULT_AUTHENTICATION_CLASSES
The `api_settings` object will check for any user-defined settings, and otherwise fall back to the default values. Any setting that uses string import paths to refer to a class will automatically import and return the referenced class, instead of the string literal.
The `api_settings` object will check for any user-defined settings, and otherwise fall back to the default values. Any setting that uses string import paths to refer to a class will automatically import and return the referenced class, instead of the string literal.
...
@@ -127,6 +127,35 @@ Default: `None`
...
@@ -127,6 +127,35 @@ Default: `None`
The name of a query parameter, which can be used by the client to override the default page size to use for pagination. If set to `None`, clients may not override the default page size.
The name of a query parameter, which can be used by the client to override the default page size to use for pagination. If set to `None`, clients may not override the default page size.
For example, given the following settings:
REST_FRAMEWORK = {
'PAGINATE_BY': 10,
'PAGINATE_BY_PARAM': 'page_size',
}
A client would be able to modify the pagination size by using the `page_size` query parameter. For example:
GET http://example.com/api/accounts?page_size=25
Default: `None`
#### MAX_PAGINATE_BY
The maximum page size to allow when the page size is specified by the client. If set to `None`, then no maximum limit is applied.
For example, given the following settings:
REST_FRAMEWORK = {
'PAGINATE_BY': 10,
'PAGINATE_BY_PARAM': 'page_size',
'MAX_PAGINATE_BY': 100
}
A client request like the following would return a paginated list of up to 100 items.
GET http://example.com/api/accounts?page_size=999
Default: `None`
Default: `None`
---
---
...
@@ -274,8 +303,56 @@ Default: `['iso-8601']`
...
@@ -274,8 +303,56 @@ Default: `['iso-8601']`
---
---
## View names and descriptions
**The following settings are used to generate the view names and descriptions, as used in responses to `OPTIONS` requests, and as used in the browsable API.**
#### VIEW_NAME_FUNCTION
A string representing the function that should be used when generating view names.
This should be a function with the following signature:
view_name(cls, suffix=None)
*`cls`: The view class. Typically the name function would inspect the name of the class when generating a descriptive name, by accessing `cls.__name__`.
*`suffix`: The optional suffix used when differentiating individual views in a viewset.
Default: `'rest_framework.views.get_view_name'`
#### VIEW_DESCRIPTION_FUNCTION
A string representing the function that should be used when generating view descriptions.
This setting can be changed to support markup styles other than the default markdown. For example, you can use it to support `rst` markup in your view docstrings being output in the browsable API.
This should be a function with the following signature:
view_description(cls, html=False)
*`cls`: The view class. Typically the description function would inspect the docstring of the class when generating a description, by accessing `cls.__doc__`
*`html`: A boolean indicating if HTML output is required. `True` when used in the browsable API, and `False` when used in generating `OPTIONS` responses.
A string representing the function that should be used when returning a response for any given exception. If the function returns `None`, a 500 error will be raised.
This setting can be changed to support error responses other than the default `{"detail": "Failure..."}` responses. For example, you can use it to provide API responses like `{"errors": [{"message": "Failure...", "code": ""} ...]}`.
This should be a function with the following signature:
Using bare status codes in your responses isn't recommended. REST framework includes a set of named constants that you can use to make more code more obvious and readable.
Using bare status codes in your responses isn't recommended. REST framework includes a set of named constants that you can use to make more code more obvious and readable.
from rest_framework import status
from rest_framework import status
from rest_framework.response import Response
def empty_view(self):
def empty_view(self):
content = {'please move along': 'nothing to see here'}
content = {'please move along': 'nothing to see here'}
The `APIRequestFactory` class supports an almost identical API to Django's standard `RequestFactory` class. This means the that standard `.get()`, `.post()`, `.put()`, `.patch()`, `.delete()`, `.head()` and `.options()` methods are all available.
The `APIRequestFactory` class supports an almost identical API to Django's standard `RequestFactory` class. This means the that standard `.get()`, `.post()`, `.put()`, `.patch()`, `.delete()`, `.head()` and `.options()` methods are all available.
from rest_framework.test import APIRequestFactory
# Using the standard RequestFactory API to create a form POST request
# Using the standard RequestFactory API to create a form POST request
@@ -72,6 +76,12 @@ To forcibly authenticate a request, use the `force_authenticate()` method.
...
@@ -72,6 +76,12 @@ To forcibly authenticate a request, use the `force_authenticate()` method.
The signature for the method is `force_authenticate(request, user=None, token=None)`. When making the call, either or both of the user and token may be set.
The signature for the method is `force_authenticate(request, user=None, token=None)`. When making the call, either or both of the user and token may be set.
For example, when forcibly authenticating using a token, you might do something like the following:
**Note**:When using `APIRequestFactory`, the object that is returned is Django's standard `HttpRequest`, and not REST framework's `Request` object, which is only generated once the view is called.
**Note**:When using `APIRequestFactory`, the object that is returned is Django's standard `HttpRequest`, and not REST framework's `Request` object, which is only generated once the view is called.
The `APIClient` class supports the same request interface as `APIRequestFactory`. This means the that standard `.get()`, `.post()`, `.put()`, `.patch()`, `.delete()`, `.head()` and `.options()` methods are all available. For example:
The `APIClient` class supports the same request interface as `APIRequestFactory`. This means the that standard `.get()`, `.post()`, `.put()`, `.patch()`, `.delete()`, `.head()` and `.options()` methods are all available. For example:
@@ -43,6 +43,10 @@ The rate descriptions used in `DEFAULT_THROTTLE_RATES` may include `second`, `mi
...
@@ -43,6 +43,10 @@ The rate descriptions used in `DEFAULT_THROTTLE_RATES` may include `second`, `mi
You can also set the throttling policy on a per-view or per-viewset basis,
You can also set the throttling policy on a per-view or per-viewset basis,
using the `APIView` class based views.
using the `APIView` class based views.
from rest_framework.response import Response
from rest_framework.throttling import UserRateThrottle
from rest_framework.views import APIView
class ExampleView(APIView):
class ExampleView(APIView):
throttle_classes = (UserRateThrottle,)
throttle_classes = (UserRateThrottle,)
...
@@ -66,6 +70,13 @@ Or, if you're using the `@api_view` decorator with function based views.
...
@@ -66,6 +70,13 @@ Or, if you're using the `@api_view` decorator with function based views.
The throttle classes provided by REST framework use Django's cache backend. You should make sure that you've set appropriate [cache settings][cache-setting]. The default value of `LocMemCache` backend should be okay for simple setups. See Django's [cache documentation][cache-docs] for more details.
The throttle classes provided by REST framework use Django's cache backend. You should make sure that you've set appropriate [cache settings][cache-setting]. The default value of `LocMemCache` backend should be okay for simple setups. See Django's [cache documentation][cache-docs] for more details.
If you need to use a cache other than `'default'`, you can do so by creating a custom throttle class and setting the `cache` attribute. For example:
class CustomAnonRateThrottle(AnonRateThrottle):
cache = get_cache('alternate')
You'll need to rememeber to also set your custom throttle class in the `'DEFAULT_THROTTLE_CLASSES'` settings key, or using the `throttle_classes` view attribute.
@@ -200,7 +200,7 @@ To run the tests against all supported configurations, first install [the tox te
...
@@ -200,7 +200,7 @@ To run the tests against all supported configurations, first install [the tox te
## Support
## Support
For support please see the [REST framework discussion group][group], try the `#restframework` channel on `irc.freenode.net`, or raise a question on [Stack Overflow][stack-overflow], making sure to include the ['django-rest-framework'][django-rest-framework-tag] tag.
For support please see the [REST framework discussion group][group], try the `#restframework` channel on `irc.freenode.net`, search [the IRC archives][botbot], or raise a question on [Stack Overflow][stack-overflow], making sure to include the ['django-rest-framework'][django-rest-framework-tag] tag.
[Paid support is available][paid-support] from [DabApps][dabapps], and can include work on REST framework core, or support with building your REST framework API. Please [contact DabApps][contact-dabapps] if you'd like to discuss commercial support options.
[Paid support is available][paid-support] from [DabApps][dabapps], and can include work on REST framework core, or support with building your REST framework API. Please [contact DabApps][contact-dabapps] if you'd like to discuss commercial support options.
...
@@ -307,6 +307,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
...
@@ -307,6 +307,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
<buttonclass="btn btn-primary js-tooltip"name="{{ api_settings.FORM_METHOD_OVERRIDE }}"value="PUT"title="Make a PUT request on the {{ name }} resource">PUT</button>
<buttonclass="btn btn-primary js-tooltip"name="{{ api_settings.FORM_METHOD_OVERRIDE }}"value="PUT"title="Make a PUT request on the {{ name }} resource">PUT</button>