One of the key benefits of class based views is the way they allow you to compose bits of reusable behaviour. REST framework takes advantage of this by providing a number of pre-built views that provide for commonly used patterns.
-
Example
-
...
+
The generic views provided by REST framework allow you to quickly build API views that map closely to your database models.
+
If the generic views don't suit the needs of your API, you can drop down to using the regular APIView class, or reuse the mixins and base classes used by the generic views to compose your own set of reusable generic views.
+
Examples
+
Typically when using the generic views, you'll override the view, and set several class attributes.
+
class UserList(generics.ListCreateAPIView):
+ serializer = UserSerializer
+ model = User
+ permissions = (IsAdminUser,)
+ paginate_by = 100
+
+
For more complex cases you might also want to override various methods on the view class. For example.
+
class UserList(generics.ListCreateAPIView):
+ serializer = UserSerializer
+ model = User
+ permissions = (IsAdminUser,)
+
+ def get_paginate_by(self):
+ """
+ Use smaller pagination for HTML representations.
+ """
+ if self.request.accepted_media_type == 'text/html':
+ return 10
+ return 100
+
+
For very simple cases you might want to pass through any class attributes using the .as_view() method. For example, your URLconf might include something the following entry.
The mixin classes provide the actions that are used
+
The mixin classes provide the actions that are used to provide the basic view behaviour. Note that the mixin classes provide action methods rather than defining the handler methods such as .get() and .post() directly. This allows for more flexible composition of behaviour.
ListModelMixin
Provides a .list(request, *args, **kwargs) method, that implements listing a queryset.
CreateModelMixin
@@ -165,8 +190,6 @@
Provides a .update(request, *args, **kwargs) method, that implements updating and saving an existing model instance.
DestroyModelMixin
Provides a .destroy(request, *args, **kwargs) method, that implements deletion of an existing model instance.
-
MetadataMixin
-
Provides a .metadata(request, *args, **kwargs) method, that returns a response containing metadata about the view.
diff --git a/api-guide/serializers.html b/api-guide/serializers.html
index 96e0c5a52..ba45269c1 100644
--- a/api-guide/serializers.html
+++ b/api-guide/serializers.html
@@ -291,6 +291,9 @@ The ModelSerializer class lets you automatically create a Serialize
class Meta:
model = Account
+ def get_pk_field(self, model_field):
+ return Field(readonly=True)
+
def get_nested_field(self, model_field):
return ModelSerializer()
diff --git a/api-guide/settings.html b/api-guide/settings.html
index dda3523d8..77e7ad60f 100644
--- a/api-guide/settings.html
+++ b/api-guide/settings.html
@@ -110,6 +110,7 @@
"There are two noncontroversial uses for overloaded POST. The first is to simulate HTTP's uniform interface for clients like web browsers that don't support PUT or DELETE"
request.content_type would return "application/json", and request.content would return "{'count': 1}"
-
Why not just use Javascript?
-
[TODO]
+
URL based accept headers
+
URL based format suffixes
Doesn't HTML5 support PUT and DELETE forms?
-
Nope. It was at one point intended to support PUT and DELETE forms, but was later dropped from the spec. There remains ongoing discussion about adding support for PUT and DELETE, as well as how to support content-types other than form-encoded data.
+
Nope. It was at one point intended to support PUT and DELETE forms, but was later dropped from the spec. There remains ongoing discussion about adding support for PUT and DELETE, as well as how to support content types other than form-encoded data.
diff --git a/tutorial/1-serialization.html b/tutorial/1-serialization.html
index d4178070c..9fda915a5 100644
--- a/tutorial/1-serialization.html
+++ b/tutorial/1-serialization.html
@@ -172,7 +172,7 @@ class Comment(models.Model):
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.
+
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 rest_framework import serializers
@@ -277,7 +277,7 @@ def comment_root(request):
return JSONResponse(serializer.errors, status=400)
Note that because we want to be able to POST to this view from clients that won't have a CSRF token we need to mark the view as csrf_exempt. This isn't something that you'd normally want to do, and REST framework views actually use more sensible behavior than this, but it'll do for our purposes right now.
-
We'll also need a view which corrosponds to an individual comment, and can be used to retrieve, update or delete the comment.
+
We'll also need a view which corresponds to an individual comment, and can be used to retrieve, update or delete the comment.
Finally we need to wire these views up, in the tutorial/urls.py file.
+
Finally we need to wire these views up. Create the blog/urls.py file:
from django.conf.urls import patterns, url
urlpatterns = patterns('blog.views',
diff --git a/tutorial/2-requests-and-responses.html b/tutorial/2-requests-and-responses.html
index e98f8d807..d98a33cd8 100644
--- a/tutorial/2-requests-and-responses.html
+++ b/tutorial/2-requests-and-responses.html
@@ -129,7 +129,7 @@ request.DATA # Handles arbitrary data. Works any HTTP request with content.
The @api_view decorator for working with function based views.
The APIView class for working with class based views.
-
These wrappers provide a few bits of functionality such as making sure you recieve Request instances in your view, and adding context to Response objects so that content negotiation can be performed.
+
These wrappers provide a few bits of functionality such as making sure you receive Request instances in your view, and adding context to Response objects so that content negotiation can be performed.
The wrappers also provide behaviour such as returning 405 Method Not Allowed responses when appropriate, and handling any ParseError exception that occurs when accessing request.DATA with malformed input.
Pulling it all together
Okay, let's go ahead and start using these new components to write a few views.
We don't necessarily need to add these extra url patterns in, but it gives us a simple, clean way of refering to a specific format.
+
We don't necessarily need to add these extra url patterns in, but it gives us a simple, clean way of referring to a specific format.
How's it looking?
Go ahead and test the API from the command line, as we did in tutorial part 1. Everything is working pretty similarly, although we've got some nicer error handling if we send invalid requests.
TODO: Describe using accept headers, content-type headers, and format suffixed URLs
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.
+
So far, so good. It looks pretty similar to the previous case, but we've got better separation between the different HTTP methods. We'll also need to update the instance view.
class CommentInstance(APIView):
"""
Retrieve, update or delete a comment instance.
@@ -223,15 +223,15 @@ class CommentRoot(mixins.ListModelMixin,
from blog.serializers import CommentSerializer
from rest_framework import generics
-class CommentRoot(generics.RootAPIView):
+class CommentRoot(generics.ListCreateAPIView):
model = Comment
serializer_class = CommentSerializer
-class CommentInstance(generics.InstanceAPIView):
+class CommentInstance(generics.RetrieveUpdateDestroyAPIView):
model = Comment
serializer_class = CommentSerializer
-
Wow, that's pretty concise. We've got a huge amount for free, and our code looks like good, clean, idomatic Django.
+
Wow, that's pretty concise. We've got a huge amount for free, and our code looks like good, clean, idiomatic Django.
Next we'll move onto part 4 of the tutorial, where we'll take a look at how we can customize the behavior of our views to support a range of authentication, permissions, throttling and other aspects.
Writing resource-orientated code can be a good thing. It helps ensure that URL conventions will be consistent across your APIs, and minimises the amount of code you need to write.
+
Writing resource-oriented code can be a good thing. It helps ensure that URL conventions will be consistent across your APIs, and minimises the amount of code you need to write.
The trade-off is that the behaviour is less explict. It can be more difficult to determine what code path is being followed, or where to override some behaviour.
Onwards and upwards.
We've reached the end of our tutorial. If you want to get more involved in the REST framework project, here's a few places you can start: