The value of request.user and request.auth for unauthenticated requests can be modified using the UNAUTHENTICATED_USER and UNAUTHENTICATED_TOKEN settings.
Setting the authentication policy
The default authentication policy may be set globally, using the DEFAULT_AUTHENTICATION setting. For example.
This policy uses HTTP Authentication with no authentication scheme. Token basic authentication is appropriate for client-server setups, such as native desktop and mobile clients. The token key should be passed in as a string to the "Authorization" HTTP header. For example:
-
curl http://my.api.org/ -X POST -H "Authorization: 0123456789abcdef0123456789abcdef"
+
curl http://my.api.org/ -X POST -H "Authorization: 0123456789abcdef0123456789abcdef"
Note: If you run TokenAuthentication in production your API must be https only, or it will be completely insecure.
If successfully authenticated, TokenAuthentication provides the following credentials.
There's no requirement for you to use them, but if you do then the self-describing API will be able to automatically hyperlink it's output for you, which makes browsing the API much easier.
reverse(viewname, request, args, *kwargs)
Has the same behavior as django.core.urlresolvers.reverse, except that it returns a fully qualified URL, using the request to determine the host and port.
-
from djangorestframework.utils import reverse
+
from djangorestframework.utils import reverse
from djangorestframework.views import APIView
class MyView(APIView):
@@ -134,6 +135,7 @@ class MyView(APIView):
================================================== -->
+
diff --git a/api-guide/serializers.html b/api-guide/serializers.html
index 4278b4ea8..8c508bd16 100644
--- a/api-guide/serializers.html
+++ b/api-guide/serializers.html
@@ -7,6 +7,7 @@
+
@@ -15,7 +16,7 @@
-
+
@@ -118,7 +119,7 @@ area would be gratefully accepted.
REST framework's serializers work very similarly to Django's Form and ModelForm classes. It provides a Serializer class which gives you a powerful, generic way to control the output of your responses, as well as a ModelSerializer class which provides a useful shortcut for creating serializers that deal with model instances and querysets.
Declaring Serializers
Let's start by creating a simple object we can use for example purposes:
We'll declare a serializer that we can use to serialize and deserialize Comment objects.
Declaring a serializer looks very similar to declaring a form:
-
class CommentSerializer(serializers.Serializer):
+
class CommentSerializer(serializers.Serializer):
email = serializers.EmailField()
content = serializers.CharField(max_length=200)
created = serializers.DateTimeField()
@@ -144,21 +145,21 @@ Declaring a serializer looks very similar to declaring a form:
The first part of serializer class defines the fields that get serialized/deserialized. The restore_object method defines how fully fledged instances get created when deserializing data. The restore_object method is optional, and is only required if we want our serializer to support deserialization.
Serializing objects
We can now use CommentSerializer to serialize a comment, or list of comments. Again, using the Serializer class looks a lot like using a Form class.
The previous example is fine for dealing with objects that only have simple datatypes, but sometimes we also need to be able to represent more complex objects,
where some of the attributes of an object might not be simple datatypes such as strings, dates or integers.
The Serializer class is itself a type of Field, and can be used to represent relationships where one object type is nested inside another.
-
class UserSerializer(serializers.Serializer):
+
class UserSerializer(serializers.Serializer):
email = serializers.EmailField()
username = serializers.CharField()
@@ -192,7 +193,7 @@ class CommentSerializer(serializers.Serializer):
If you want to create a custom field, you'll probably want to override either one or both of the .to_native() and .from_native() methods. These two methods are used to convert between the intial datatype, and a primative, serializable datatype. Primative datatypes may be any of a number, string, date/time/datetime or None. They may also be any list or dictionary like object that only contains other primative objects.
The .to_native() method is called to convert the initial datatype into a primative, serializable datatype. The from_native() method is called to restore a primative datatype into it's initial representation.
Let's look at an example of serializing a class that represents an RGB color value:
-
class Color(object):
+
class Color(object):
"""
A color represented in the RGB colorspace.
"""
@@ -217,7 +218,7 @@ class ColourField(Field):
By default field values are treated as mapping to an attribute on the object. If you need to customize how the field value is accessed and set you need to override .field_to_native() and/or .field_from_native().
As an example, let's create a field that can be used represent the class name of the object being serialized:
-
class ClassNameField(Field):
+
class ClassNameField(Field):
def field_to_native(self, obj, field_name):
"""
Serialize the object's class name, not an attribute of the object.
@@ -234,14 +235,14 @@ class ColourField(Field):
ModelSerializers
Often you'll want serializer classes that map closely to model definitions.
The ModelSerializer class lets you automatically create a Serializer class with fields that corrospond to the Model fields.
-
class AccountSerializer(ModelSerializer):
+
class AccountSerializer(ModelSerializer):
class Meta:
model = Account
[TODO: Explain model field to serializer field mapping in more detail]
Specifying fields explicitly
You can add extra fields to a ModelSerializer or override the default fields by declaring fields on the class, just as you would for a Serializer class.
-
class AccountSerializer(ModelSerializer):
+
class AccountSerializer(ModelSerializer):
url = CharField(source='get_absolute_url', readonly=True)
group = NaturalKeyField()
@@ -259,7 +260,7 @@ The ModelSerializer class lets you automatically create a Serialize
Specifying which fields should be included
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.
For example:
-
class AccountSerializer(ModelSerializer):
+
class AccountSerializer(ModelSerializer):
class Meta:
model = Account
exclude = ('id',)
@@ -268,7 +269,7 @@ The ModelSerializer class lets you automatically create a Serialize
[TODO: Possibly only allow .serialize(fields=…) in FixtureSerializer for backwards compatability, but remove for ModelSerializer]
Specifiying nested serialization
The default ModelSerializer uses primary keys for relationships, but you can also easily generate nested representations using the nested option:
-
class AccountSerializer(ModelSerializer):
+
class AccountSerializer(ModelSerializer):
class Meta:
model = Account
exclude = ('id',)
@@ -279,7 +280,7 @@ The ModelSerializer class lets you automatically create a Serialize
The nested option may also be set by passing it to the serialize() method.
[TODO: Possibly only allow .serialize(nested=…) in FixtureSerializer]
Customising the default fields used by a ModelSerializer
-
class AccountSerializer(ModelSerializer):
+
class AccountSerializer(ModelSerializer):
class Meta:
model = Account
@@ -300,6 +301,7 @@ The ModelSerializer class lets you automatically create a Serialize
================================================== -->
+
diff --git a/api-guide/settings.html b/api-guide/settings.html
index a8bb43b33..4f1fa002d 100644
--- a/api-guide/settings.html
+++ b/api-guide/settings.html
@@ -7,6 +7,7 @@
+
@@ -15,7 +16,7 @@
-
+
@@ -112,7 +113,7 @@
Settings
Configuration for REST framework is all namespaced inside the API_SETTINGS setting.
For example your project's settings.py file might look like this:
A list or tuple of authentication classes, that determines the default set of authenticators used when accessing the request.user or request.auth properties.
— RFC 2324, Hyper Text Coffee Pot Control Protocol
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 djangorestframework import status
+
from djangorestframework import status
def empty_view(self):
content = {'please move along': 'nothing to see here'}
@@ -116,12 +117,12 @@ def empty_view(self):
and RFC 6585.
Informational - 1xx
This class of status code indicates a provisional response. There are no 1xx status codes used in REST framework by default.
-
HTTP_100_CONTINUE
+
HTTP_100_CONTINUE
HTTP_101_SWITCHING_PROTOCOLS
Successful - 2xx
This class of status code indicates that the client's request was successfully received, understood, and accepted.
The 4xx class of status code is intended for cases in which the client seems to have erred. Except when responding to a HEAD request, the server SHOULD include an entity containing an explanation of the error situation, and whether it is a temporary or permanent condition.
Response status codes beginning with the digit "5" indicate cases in which the server is aware that it has erred or is incapable of performing the request. Except when responding to a HEAD request, the server SHOULD include an entity containing an explanation of the error situation, and whether it is a temporary or permanent condition.
If you're intending to use the browserable API you'll want to add REST framework's login and logout views. Add the following to your root urls.py file.
This tutorial will walk you through the building blocks that make up REST framework. It'll take a little while to get through, but it'll give you a comprehensive understanding of how everything fits together.
Setting up a new environment
Before we do anything else we'll create a new virtual environment, using virtualenv. This will make sure our package configuration is keep nicely isolated from any other projects we're working on.
Note: To exit the virtualenv environment at any time, just type deactivate. For more information see the virtualenv documentation.
Getting started
Okay, we're ready to get coding.
To get started, let's create a new project to work with.
-
django-admin.py startproject tutorial
+
django-admin.py startproject tutorial
cd tutorial
Once that's done we can create an app that we'll use to create a simple Web API.
-
python manage.py startapp blog
+
python manage.py startapp blog
The simplest way to get up and running will probably be to use an sqlite3 database for the tutorial. Edit the tutorial/settings.py file, and set the default database "ENGINE" to "sqlite3", and "NAME" to "tmp.db".
For the purposes of this tutorial we're going to start by creating a simple Comment model that is used to store comments against a blog post. Go ahead and edit the blog app's models.py file.
-
from django.db import models
+
from django.db import models
class Comment(models.Model):
email = models.EmailField()
@@ -161,11 +163,11 @@ class Comment(models.Model):
created = models.DateTimeField(auto_now_add=True)
Don't forget to sync the database for the first time.
-
python manage.py syncdb
+
python manage.py syncdb
Creating a Serializer class
We're going to create a simple Web API that we can use to edit these comment objects with. The first thing we need is a way of serializing and deserializing the objects into representations such as json. We do this by declaring serializers, that work very similarly to Django's forms. Create a file in the project named serializers.py and add the following.
-
from blog import models
+
from blog import models
from djangorestframework import serializers
class CommentSerializer(serializers.Serializer):
@@ -189,10 +191,10 @@ class CommentSerializer(serializers.Serializer):
Working with Serializers
Before we go any further we'll familiarise ourselves with using our new Serializer class. Let's drop into the Django shell.
-
python manage.py shell
+
python manage.py shell
Okay, once we've got a few imports out of the way, we'd better create a few comments to work with.
-
from blog.models import Comment
+
from blog.models import Comment
from blog.serializers import CommentSerializer
from djangorestframework.renderers import JSONRenderer
from djangorestframework.parsers import JSONParser
@@ -205,20 +207,20 @@ c2.save()
c3.save()
We've now got a few comment instances to play with. Let's take a look at serializing one of those instances.
Let's see how we can write some API views using our new Serializer class.
We'll start off by creating a subclass of HttpResponse that we can use to render any data we return into json.
Edit the blog/views.py file, and add the following.
-
from blog.models import Comment
+
from blog.models import Comment
from blog.serializers import CommentSerializer
from djangorestframework.renderers import JSONRenderer
from djangorestframework.parsers import JSONParser
@@ -246,7 +248,7 @@ class JSONResponse(HttpResponse):
super(JSONResponse, self).__init__(content, **kwargs)
The root of our API is going to be a view that supports listing all the existing comments, or creating a new comment.
-
def comment_root(request):
+
def comment_root(request):
"""
List all comments, or create a new comment.
"""
@@ -266,7 +268,7 @@ class JSONResponse(HttpResponse):
return JSONResponse(serializer.error_data, status=400)
We'll also need a view which corrosponds to an individual comment, and can be used to retrieve, update or delete the comment.
-
def comment_instance(request, pk):
+
def comment_instance(request, pk):
"""
Retrieve, update or delete a comment instance.
"""
@@ -294,7 +296,7 @@ class JSONResponse(HttpResponse):
return HttpResponse(status=204)
Finally we need to wire these views up, in the tutorial/urls.py file.
@@ -107,12 +108,12 @@
Let's introduce a couple of essential building blocks.
Request objects
REST framework intoduces a Request object that extends the regular HttpRequest, and provides more flexible request parsing. The core functionality of the Request object is the request.DATA attribute, which is similar to request.POST, but more useful for working with Web APIs.
-
request.POST # Only handles form data. Only works for 'POST' method.
+
request.POST # Only handles form data. Only works for 'POST' method.
request.DATA # Handles arbitrary data. Works any HTTP request with content.
Response objects
REST framework also introduces a Response object, which is a type of TemplateResponse that takes unrendered content and uses content negotiation to determine the correct content type to return to the client.
-
return Response(data) # Renders to content type as requested by the client.
+
return Response(data) # Renders to content type as requested by the client.
Status codes
Using numeric HTTP status codes in your views doesn't always make for obvious reading, and it's easy to not notice if you get an error code wrong. REST framework provides more explicit identifiers for each status code, such as HTTP_400_BAD_REQUEST in the status module. It's a good idea to use these throughout rather than using numeric identifiers.
@@ -127,7 +128,7 @@ request.DATA # Handles arbitrary data. Works any HTTP request with content.
Pulling it all together
Okay, let's go ahead and start using these new components to write a few views.
We don't need our JSONResponse class anymore, so go ahead and delete that. Once that's done we can start refactoring our views slightly.
-
from blog.models import Comment
+
from blog.models import Comment
from blog.serializers import CommentSerializer
from djangorestframework import status
from djangorestframework.decorators import api_view
@@ -153,7 +154,7 @@ def comment_root(request):
return Response(serializer.error_data, status=status.HTTP_400_BAD_REQUEST)
Our instance view is an improvement over the previous example. It's a little more concise, and the code now feels very similar to if we were working with the Forms API. We're also using named status codes, which makes the response meanings more obvious.
To take advantage of the fact that our responses are no longer hardwired to a single content type let's add support for format suffixes to our API endpoints. Using format suffixes gives us URLs that explicitly refer to a given format, and means our API will be able to handle URLs such as http://example.com/api/items/4.json.
Start by adding a format keyword argument to both of the views, like so.
-
def comment_root(request, format=None):
+
def comment_root(request, format=None):
and
-
def comment_instance(request, pk, format=None):
+
def comment_instance(request, pk, format=None):
Now update the urls.py file slightly, to append a set of format_suffix_patterns in addition to the existing URLs.
We can also write our API views using class based views, rather than function based views. As we'll see this is a powerful pattern that allows us to reuse common functionality, and helps us keep our code DRY.
Rewriting our API using class based views
We'll start by rewriting the root view as a class based view. All this involves is a little bit of refactoring.
-
from blog.models import Comment
+
from blog.models import Comment
from blog.serializers import CommentSerializer
from django.http import Http404
from djangorestframework.views import APIView
@@ -128,7 +129,7 @@ class CommentRoot(APIView):
comment_root = CommentRoot.as_view()
So far, so good. It looks pretty similar to the previous case, but we've got better seperation between the different HTTP methods. We'll also need to update the instance view.
-
class CommentInstance(APIView):
+
class CommentInstance(APIView):
"""
Retrieve, update or delete a comment instance.
"""
@@ -166,7 +167,7 @@ Okay, we're done. If you run the development server everything should be workin
One of the big wins of using class based views is that it allows us to easily compose reusable bits of behaviour.
The create/retrieve/update/delete operations that we've been using so far are going to be pretty simliar for any model-backed API views we create. Those bits of common behaviour are implemented in REST framework's mixin classes.
Let's take a look at how we can compose our views by using the mixin classes.
-
from blog.models import Comment
+
from blog.models import Comment
from blog.serializers import CommentSerializer
from djangorestframework import mixins
from djangorestframework import generics
@@ -187,7 +188,7 @@ comment_root = CommentRoot.as_view()
We'll take a moment to examine exactly what's happening here - We're building our view using MultipleObjectBaseView, and adding in ListModelMixin and CreateModelMixin.
The base class provides the core functionality, and the mixin classes provide the .list() and .create() actions. We're then explictly binding the get and post methods to the appropriate actions. Simple enough stuff so far.
-
class CommentInstance(mixins.RetrieveModelMixin,
+
Pretty similar. This time we're using the SingleObjectBaseView class to provide the core functionality, and adding in mixins to provide the .retrieve(), .update() and .destroy() actions.
Using generic class based views
Using the mixin classes we've rewritten the views to use slightly less code than before, but we can go one step further. REST framework provides a set of already mixed-in generic views that we can use.
class BlogPostSerializer(URLModelSerializer):
class Meta:
model = BlogPost
@@ -105,7 +106,7 @@ class CommentSerializer(URLModelSerializer):
model = Comment
resources.py
-
class BlogPostResource(ModelResource):
+
class BlogPostResource(ModelResource):
serializer_class = BlogPostSerializer
model = BlogPost
permissions = [AdminOrAnonReadonly()]
@@ -118,7 +119,7 @@ class CommentResource(ModelResource):
throttles = [AnonThrottle(rate='5/min')]
Now that we're using Resources rather than Views, we don't need to design the urlconf ourselves. The conventions for wiring up resources into views and urls are handled automatically. All we need to do is register the appropriate resources with a router, and let it do the rest. Here's our re-wired urls.py file.
-
from blog import resources
+
from blog import resources
from djangorestframework.routers import DefaultRouter
router = DefaultRouter()
@@ -145,6 +146,7 @@ urlpatterns = router.urlpatterns
================================================== -->
+