One of the key benefits of classbased views is the way they allow you to compose bits of reusable behavior. REST framework takes advantage of this by providing a number of pre-built views that provide for commonly used patterns.
One of the key benefits of class-based views is the way they allow you to compose bits of reusable behavior. REST framework takes advantage of this by providing a number of pre-built views that provide for commonly used patterns.
The generic views provided by REST framework allow you to quickly build API views that map closely to your database models.
The generic views provided by REST framework allow you to quickly build API views that map closely to your database models.
@@ -876,7 +876,7 @@ There are four methods that can be overridden, depending on what functionality y
...
@@ -876,7 +876,7 @@ There are four methods that can be overridden, depending on what functionality y
*`.to_internal_value()` - Override this to support deserialization, for write operations.
*`.to_internal_value()` - Override this to support deserialization, for write operations.
*`.create()` and `.update()` - Override either or both of these to support saving instances.
*`.create()` and `.update()` - Override either or both of these to support saving instances.
Because this class provides the same interface as the `Serializer` class, you can use it with the existing generic classbased views exactly as you would for a regular `Serializer` or `ModelSerializer`.
Because this class provides the same interface as the `Serializer` class, you can use it with the existing generic class-based views exactly as you would for a regular `Serializer` or `ModelSerializer`.
The only difference you'll notice when doing so is the `BaseSerializer` classes will not generate HTML forms in the browsable API. This is because the data they return does not include all the field information that would allow each field to be rendered into a suitable HTML input.
The only difference you'll notice when doing so is the `BaseSerializer` classes will not generate HTML forms in the browsable API. This is because the data they return does not include all the field information that would allow each field to be rendered into a suitable HTML input.
@@ -265,9 +265,9 @@ A validator may be any callable that raises a `serializers.ValidationError` on f
...
@@ -265,9 +265,9 @@ A validator may be any callable that raises a `serializers.ValidationError` on f
if value % 2 != 0:
if value % 2 != 0:
raise serializers.ValidationError('This field must be an even number.')
raise serializers.ValidationError('This field must be an even number.')
## Classbased
## Class-based
To write a class based validator, use the `__call__` method. Class based validators are useful as they allow you to parameterize and reuse behavior.
To write a class-based validator, use the `__call__` method. Class-based validators are useful as they allow you to parameterize and reuse behavior.
class MultipleOf(object):
class MultipleOf(object):
def __init__(self, base):
def __init__(self, base):
...
@@ -280,7 +280,7 @@ To write a class based validator, use the `__call__` method. Class based validat
...
@@ -280,7 +280,7 @@ To write a class based validator, use the `__call__` method. Class based validat
#### Using `set_context()`
#### Using `set_context()`
In some advanced cases you might want a validator to be passed the serializer field it is being used with as additional context. You can do so by declaring a `set_context` method on a classbased validator.
In some advanced cases you might want a validator to be passed the serializer field it is being used with as additional context. You can do so by declaring a `set_context` method on a class-based validator.
def set_context(self, serializer_field):
def set_context(self, serializer_field):
# Determine if this is an update or a create operation.
# Determine if this is an update or a create operation.
@@ -426,7 +426,7 @@ There are four methods that can be overridden, depending on what functionality y
...
@@ -426,7 +426,7 @@ There are four methods that can be overridden, depending on what functionality y
*`.to_internal_value()` - Override this to support deserialization, for write operations.
*`.to_internal_value()` - Override this to support deserialization, for write operations.
*`.create()` and `.update()` - Override either or both of these to support saving instances.
*`.create()` and `.update()` - Override either or both of these to support saving instances.
Because this class provides the same interface as the `Serializer` class, you can use it with the existing generic classbased views exactly as you would for a regular `Serializer` or `ModelSerializer`.
Because this class provides the same interface as the `Serializer` class, you can use it with the existing generic class-based views exactly as you would for a regular `Serializer` or `ModelSerializer`.
The only difference you'll notice when doing so is the `BaseSerializer` classes will not generate HTML forms in the browsable API. This is because the data they return does not include all the field information that would allow each field to be rendered into a suitable HTML input.
The only difference you'll notice when doing so is the `BaseSerializer` classes will not generate HTML forms in the browsable API. This is because the data they return does not include all the field information that would allow each field to be rendered into a suitable HTML input.
...
@@ -801,7 +801,7 @@ This change means that you can now easily customize the style of error responses
...
@@ -801,7 +801,7 @@ This change means that you can now easily customize the style of error responses
## The metadata API
## The metadata API
Behavior for dealing with `OPTIONS` requests was previously built directly into the classbased views. This has now been properly separated out into a Metadata API that allows the same pluggable style as other API policies in REST framework.
Behavior for dealing with `OPTIONS` requests was previously built directly into the class-based views. This has now been properly separated out into a Metadata API that allows the same pluggable style as other API policies in REST framework.
This makes it far easier to use a different style for `OPTIONS` responses throughout your API, and makes it possible to create third-party metadata policies.
This makes it far easier to use a different style for `OPTIONS` responses throughout your API, and makes it possible to create third-party metadata policies.
@@ -25,7 +25,7 @@ Using numeric HTTP status codes in your views doesn't always make for obvious re
...
@@ -25,7 +25,7 @@ Using numeric HTTP status codes in your views doesn't always make for obvious re
REST framework provides two wrappers you can use to write API views.
REST framework provides two wrappers you can use to write API views.
1. The `@api_view` decorator for working with function based views.
1. The `@api_view` decorator for working with function based views.
2. The `APIView` class for working with classbased views.
2. The `APIView` class for working with class-based views.
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.
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.
...
@@ -200,7 +200,7 @@ See the [browsable api][browsable-api] topic for more information about the brow
...
@@ -200,7 +200,7 @@ See the [browsable api][browsable-api] topic for more information about the brow
## What's next?
## What's next?
In [tutorial part 3][tut-3], we'll start using classbased views, and see how generic views reduce the amount of code we need to write.
In [tutorial part 3][tut-3], we'll start using class-based views, and see how generic views reduce the amount of code we need to write.
We can also write our API views using classbased 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][dry].
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][dry].
## Rewriting our API using classbased views
## Rewriting our API using class-based views
We'll start by rewriting the root view as a classbased view. All this involves is a little bit of refactoring of `views.py`.
We'll start by rewriting the root view as a class-based view. All this involves is a little bit of refactoring of `views.py`.
from snippets.models import Snippet
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from snippets.serializers import SnippetSerializer
...
@@ -62,7 +62,7 @@ So far, so good. It looks pretty similar to the previous case, but we've got be
...
@@ -62,7 +62,7 @@ So far, so good. It looks pretty similar to the previous case, but we've got be
That's looking good. Again, it's still pretty similar to the function based view right now.
That's looking good. Again, it's still pretty similar to the function based view right now.
We'll also need to refactor our `urls.py` slightly now we're using classbased views.
We'll also need to refactor our `urls.py` slightly now we're using class-based views.
from django.conf.urls import url
from django.conf.urls import url
from rest_framework.urlpatterns import format_suffix_patterns
from rest_framework.urlpatterns import format_suffix_patterns
...
@@ -79,7 +79,7 @@ Okay, we're done. If you run the development server everything should be workin
...
@@ -79,7 +79,7 @@ Okay, we're done. If you run the development server everything should be workin
## Using mixins
## Using mixins
One of the big wins of using classbased views is that it allows us to easily compose reusable bits of behaviour.
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 similar for any model-backed API views we create. Those bits of common behaviour are implemented in REST framework's mixin classes.
The create/retrieve/update/delete operations that we've been using so far are going to be pretty similar for any model-backed API views we create. Those bits of common behaviour are implemented in REST framework's mixin classes.
...
@@ -124,7 +124,7 @@ The base class provides the core functionality, and the mixin classes provide th
...
@@ -124,7 +124,7 @@ The base class provides the core functionality, and the mixin classes provide th
Pretty similar. Again we're using the `GenericAPIView` class to provide the core functionality, and adding in mixins to provide the `.retrieve()`, `.update()` and `.destroy()` actions.
Pretty similar. Again we're using the `GenericAPIView` class to provide the core functionality, and adding in mixins to provide the `.retrieve()`, `.update()` and `.destroy()` actions.
## Using generic classbased views
## 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 to trim down our `views.py` module even more.
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 to trim down our `views.py` module even more.
@@ -67,7 +67,7 @@ Now that we've got some users to work with, we'd better add representations of t
...
@@ -67,7 +67,7 @@ Now that we've got some users to work with, we'd better add representations of t
Because `'snippets'` is a *reverse* relationship on the User model, it will not be included by default when using the `ModelSerializer` class, so we needed to add an explicit field for it.
Because `'snippets'` is a *reverse* relationship on the User model, it will not be included by default when using the `ModelSerializer` class, so we needed to add an explicit field for it.
We'll also add a couple of views to `views.py`. We'd like to just use read-only views for the user representations, so we'll use the `ListAPIView` and `RetrieveAPIView` generic classbased views.
We'll also add a couple of views to `views.py`. We'd like to just use read-only views for the user representations, so we'll use the `ListAPIView` and `RetrieveAPIView` generic class-based views.
@@ -104,7 +104,7 @@ Okay, now let's wire up the API URLs. On to `tutorial/urls.py`...
...
@@ -104,7 +104,7 @@ Okay, now let's wire up the API URLs. On to `tutorial/urls.py`...
Because we're using viewsets instead of views, we can automatically generate the URL conf for our API, by simply registering the viewsets with a router class.
Because we're using viewsets instead of views, we can automatically generate the URL conf for our API, by simply registering the viewsets with a router class.
Again, if we need more control over the API URLs we can simply drop down to using regular classbased views, and writing the URL conf explicitly.
Again, if we need more control over the API URLs we can simply drop down to using regular class-based views, and writing the URL conf explicitly.
Finally, we're including default login and logout views for use with the browsable API. That's optional, but useful if your API requires authentication and you want to use the browsable API.
Finally, we're including default login and logout views for use with the browsable API. That's optional, but useful if your API requires authentication and you want to use the browsable API.