# DRF

## DRF

Makes it easy to:

* **serialize** objects to JSON
* **deseralize** from JSON to objects

## Class-based Views

DRF provides an `APIView` class, which subclasses Django's `View` class.

### `APIView` vs regular `View` classes:

* Requests passed to the handler methods will be REST framework's `Request` instances, not Django's `HttpRequest`instances.
* Handler methods may return REST framework's `Response`, instead of Django's `HttpResponse`. The view will manage content negotiation and setting the correct renderer on the response.
* Any `APIException` exceptions will be caught and mediated into appropriate responses.
* Incoming requests will be authenticated and appropriate permission and/or throttle checks will be run before dispatching the request to the handler method.

Using the `APIView` class is pretty much the same as using a regular `View` class, as usual, the incoming request is dispatched to an appropriate handler method such as `.get()` or `.post()`. Additionally, a number of attributes may be set on the class that control various aspects of the API policy.

### Example

```python
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import authentication, permissions
from django.contrib.auth.models import User

class ListUsers(APIView):
    """
    View to list all users in the system.

    * Requires token authentication.
    * Only admin users are able to access this view.
    """
    authentication_classes = (authentication.TokenAuthentication,)
    permission_classes = (permissions.IsAdminUser,)

    def get(self, request, format=None):
        """
        Return a list of all users.
        """
        usernames = [user.username for user in User.objects.all()]
        return Response(usernames)
```

## Function Based Views

DRF also allows you to work with regular function based views. It provides a set of simple **decorators** that wrap your function based views to ensure they receive an instance of `Request` (rather than the usual Django `HttpRequest`) and allows them to return a `Response` (instead of a Django `HttpResponse`), and allow you to configure how the request is processed.

### [@api\_view()](https://www.django-rest-framework.org/api-guide/views/#api_view) <a href="#api_view" id="api_view"></a>

**Signature:** `@api_view(http_method_names=['GET'])`

Decorator, which takes a list of HTTP methods that your view should respond to.

Example: simple view that just manually returns some data:

```python
from rest_framework.decorators import api_view

@api_view()
def hello_world(request):
    return Response({"message": "Hello, world!"})
```

This view will use the default renderers, parsers, authentication classes etc specified in the [settings](https://www.django-rest-framework.org/api-guide/settings/).

By default only `GET` methods will be accepted. Other methods will respond with "405 Method Not Allowed". To alter this behaviour, specify which methods the view allows, like so:

```python
@api_view(['GET', 'POST'])
def hello_world(request):
    if request.method == 'POST':
        return Response({"message": "Got some data!", "data": request.data})
    return Response({"message": "Hello, world!"})
```

## Viewsets

DRF allows you to combine the logic for a set of related views in a single class, called a `ViewSet`. In other frameworks called 'Resources' or 'Controllers'.

&#x20;**A type of class-based View, that does not provide any method handlers** such as `.get()` or `.post()`, and instead provides actions such as `.list()` and `.create()`.

The method handlers for a `ViewSet` are only bound to the corresponding actions at the point of finalizing the view, using the `.as_view()` method.

Typically, rather than explicitly registering the views in a viewset in the urlconf, you'll register the viewset with a router class, that automatically determines the urlconf for you.

### [Example](https://www.django-rest-framework.org/api-guide/viewsets/#example) <a href="#example" id="example"></a>

Let's define a simple viewset that can be used to list or retrieve all the users in the system.

```
from django.contrib.auth.models import User
from django.shortcuts import get_object_or_404
from myapps.serializers import UserSerializer
from rest_framework import viewsets
from rest_framework.response import Response

class UserViewSet(viewsets.ViewSet):
    """
    A simple ViewSet for listing or retrieving users.
    """
    def list(self, request):
        queryset = User.objects.all()
        serializer = UserSerializer(queryset, many=True)
        return Response(serializer.data)

    def retrieve(self, request, pk=None):
        queryset = User.objects.all()
        user = get_object_or_404(queryset, pk=pk)
        serializer = UserSerializer(user)
        return Response(serializer.data)
```

If we need to, we can bind this viewset into two separate views, like so:

```
user_list = UserViewSet.as_view({'get': 'list'})
user_detail = UserViewSet.as_view({'get': 'retrieve'})
```

Typically we wouldn't do this, but would instead register the viewset with a router, and allow the urlconf to be automatically generated.

```
from myapp.views import UserViewSet
from rest_framework.routers import DefaultRouter

router = DefaultRouter()
router.register(r'users', UserViewSet, basename='user')
urlpatterns = router.urls
```

Rather than writing your own viewsets, you'll often want to use the existing base classes that provide a default set of behavior. For example:

```
class UserViewSet(viewsets.ModelViewSet):
    """
    A viewset for viewing and editing user instances.
    """
    serializer_class = UserSerializer
    queryset = User.objects.all()
```

2 advantages of using a `ViewSet` class over using a `View` class.

* **Repeated logic can be combined into a single class**. In the above example, we only need to specify the `queryset` once, and it'll be used across multiple views.
* By using **routers**, we no longer need to deal with wiring up the URL conf ourselves.

Both of these come with a **trade-off. Using regular views and URL confs is more explicit and gives you more control**. ViewSets are helpful if you want to get up and running quickly, or when you have a large API and you want to enforce a consistent URL configuration throughout.

### [ViewSet actions](https://www.django-rest-framework.org/api-guide/viewsets/#viewset-actions) <a href="#viewset-actions" id="viewset-actions"></a>

The default routers included with REST framework will provide routes for a standard set of create/retrieve/update/destroy style actions, as shown below:

```python
class UserViewSet(viewsets.ViewSet):
    """
    Example empty viewset demonstrating the standard
    actions that will be handled by a router class.

    If you're using format suffixes, make sure to also include
    the `format=None` keyword argument for each action.
    """

    def list(self, request):
        pass

    def create(self, request):
        pass

    def retrieve(self, request, pk=None):
        pass

    def update(self, request, pk=None):
        pass

    def partial_update(self, request, pk=None):
        pass

    def destroy(self, request, pk=None):
        pass
```

### [Introspecting ViewSet actions](https://www.django-rest-framework.org/api-guide/viewsets/#introspecting-viewset-actions) <a href="#introspecting-viewset-actions" id="introspecting-viewset-actions"></a>

During **dispatch**, the following attributes are available on the `ViewSet`.

* `basename` - the base to use for the URL names that are created.
* `action` - the name of the current action (e.g., `list`, `create`).
* `detail` - boolean indicating if the current action is configured for a list or detail view.
* `suffix` - the display suffix for the viewset type - mirrors the `detail` attribute.
* `name` - the display name for the viewset. This argument is mutually exclusive to `suffix`.
* `description` - the display description for the individual view of a viewset.

You may inspect these attributes to adjust behaviour based on the current action. Example, restrict permissions to everything except the `list`:

```python
def get_permissions(self):
    """
    Instantiates and returns the list of permissions that this view requires.
    """
    if self.action == 'list':
        permission_classes = [IsAuthenticated]
    else:
        permission_classes = [IsAdmin]
    return [permission() for permission in permission_classes]
```

## Serializers

### Definitinon

Allow complex data such as querysets and model instances to be converted to native Python datatypes that can then be easily rendered into `JSON`, `XML` or other content types.

Also provide deserialization, allowing parsed data to be converted back into complex types, after first validating the incoming data.

### Declaration

```python
from rest_framework import serializers

class CommentSerializer(serializers.Serializer):
    email = serializers.EmailField()
    content = serializers.CharField(max_length=200)
    created = serializers.DateTimeField()
```

### Serialization

```python
serializer = CommentSerializer(comment)
serializer.data
# {'email': 'leila@example.com', 'content': 'foo bar', 'created': '2016-01-27T15:17:10.375877'}
```

At this point we've translated the model instance into Python native datatypes. To finalise the serialization process we render the data into `json`.

```python
from rest_framework.renderers import JSONRenderer

json = JSONRenderer().render(serializer.data)
json
# b'{"email":"leila@example.com","content":"foo bar","created":"2016-01-27T15:17:10.375877"}'
```

### Deserializing objects

1st. Parse a stream into Python native datatypes...

```python
import io
from rest_framework.parsers import JSONParser

stream = io.BytesIO(json)
data = JSONParser().parse(stream)
```

2nd. restore those native datatypes into a dictionary of validated data.

```python
serializer = CommentSerializer(data=data)
serializer.is_valid()
# True
serializer.validated_data
# {'content': 'foo bar', 'email': 'leila@example.com', 'created': datetime.datetime(2012, 08, 22, 16, 20, 09, 822243)}
```

**Validation.** When deserializing objects, you always need to call **`is_valid()`** before attempting to access the validated data, or save an object instance:

```python
serializer = CommentSerializer(data={'email': 'foobar', 'content': 'baz'})
serializer.is_valid()
# False
serializer.errors
# {'email': ['Enter a valid e-mail address.'], 'created': ['This field is required.']}
```

## Dealing with nested objects

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.

```python
class UserSerializer(serializers.Serializer):
    email = serializers.EmailField()
    username = serializers.CharField(max_length=100)

class CommentSerializer(serializers.Serializer):
    user = UserSerializer()
    content = serializers.CharField(max_length=200)
    created = serializers.DateTimeField()
```

If a nested representation may optionally accept the `None` value you should pass the `required=False` flag to the nested serializer.

```python
class CommentSerializer(serializers.Serializer):
    user = UserSerializer(required=False)  # May be an anonymous user.
    content = serializers.CharField(max_length=200)
    created = serializers.DateTimeField()
```

Similarly if a nested representation should be a list of items, you should pass the `many=True` flag to the nested serialized.

```python
class CommentSerializer(serializers.Serializer):
    user = UserSerializer(required=False)
    edits = EditItemSerializer(many=True)  # A nested list of 'edit' items.
    content = serializers.CharField(max_length=200)
    created = serializers.DateTimeField()
```

### [Writable nested representations](https://www.django-rest-framework.org/api-guide/serializers/#writable-nested-representations) <a href="#writable-nested-representations" id="writable-nested-representations"></a>

When dealing with nested representations that support deserializing the data, any errors with nested objects will be nested under the field name of the nested object.

```python
serializer = CommentSerializer(data={'user': {'email': 'foobar', 'username': 'doe'}, 'content': 'baz'})
serializer.is_valid()
# False
serializer.errors
# {'user': {'email': ['Enter a valid e-mail address.']}, 'created': ['This field is required.']}
```

Similarly, the `.validated_data` property will include nested data structures.

**Writing .create() methods for nested representations**

If you're supporting writable nested representations you'll need to write `.create()` or `.update()` methods that handle saving multiple objects.

Example: handling creating a user with a nested profile object:

```python
class UserSerializer(serializers.ModelSerializer):
    profile = ProfileSerializer()

    class Meta:
        model = User
        fields = ('username', 'email', 'profile')

    def create(self, validated_data):
        profile_data = validated_data.pop('profile')
        user = User.objects.create(**validated_data)
        Profile.objects.create(user=user, **profile_data)
        return user
```

**Writing .update() methods for nested representations**

For updates you'll want to think carefully about how to handle updates to relationships. For example if the data for the relationship is `None`, or not provided, which of the following should occur?

* Set the relationship to `NULL` in the database.
* Delete the associated instance.
* Ignore the data and leave the instance as it is.
* Raise a validation error.

Example: an `.update()` method on our previous `UserSerializer` class.

```python
    def update(self, instance, validated_data):
        profile_data = validated_data.pop('profile')
        # Unless the application properly enforces that this field is
        # always set, the follow could raise a `DoesNotExist`, which
        # would need to be handled.
        profile = instance.profile

        instance.username = validated_data.get('username', instance.username)
        instance.email = validated_data.get('email', instance.email)
        instance.save()

        profile.is_premium_member = profile_data.get(
            'is_premium_member',
            profile.is_premium_member
        )
        profile.has_support_contract = profile_data.get(
            'has_support_contract',
            profile.has_support_contract
         )
        profile.save()

        return instance
```

Because the behavior of nested creates and updates can be ambiguous, and may require complex dependencies between related models, REST framework 3 requires you to always write these methods explicitly. The default `ModelSerializer` `.create()` and `.update()` methods do not include support for writable nested representations.

There are however, third-party packages available such as [DRF Writable Nested](https://www.django-rest-framework.org/api-guide/serializers/#drf-writable-nested) that support automatic writable nested representations.

**Handling saving related instances in model manager classes**

An alternative to saving multiple related instances in the serializer is to write custom model manager classes that handle creating the correct instances.

For example, suppose we wanted to ensure that `User` instances and `Profile` instances are always created together as a pair. We might write a custom manager class that looks something like this:

```python
class UserManager(models.Manager):
    ...

    def create(self, username, email, is_premium_member=False, has_support_contract=False):
        user = User(username=username, email=email)
        user.save()
        profile = Profile(
            user=user,
            is_premium_member=is_premium_member,
            has_support_contract=has_support_contract
        )
        profile.save()
        return user
```

This manager class now more nicely encapsulates that user instances and profile instances are always created at the same time. Our `.create()` method on the serializer class can now be re-written to use the new manager method.

```python
def create(self, validated_data):
    return User.objects.create(
        username=validated_data['username'],
        email=validated_data['email']
        is_premium_member=validated_data['profile']['is_premium_member']
        has_support_contract=validated_data['profile']['has_support_contract']
    )
```

For more details on this approach see the Django documentation on [model managers](https://docs.djangoproject.com/en/stable/topics/db/managers/), and [this blogpost on using model and manager classes](https://www.dabapps.com/blog/django-models-and-encapsulation/).

## API Views

Django views that will use the previously created class to class to return JSON representation for each HTTP request that our API will handle.

## Authentication

## Throttling

DRF provedes 3 throttling classes:

1. **AnonRateThrottle**: limits the rate of request that an **anonymous user** can make requests
2. **UserRateThrotle:** limits the rate of request that a **specific user** can make requests
3. **ScopedRateThrottle:** limits the rate of requests for specific parts of the API identified

##


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ricardomol.gitbook.io/notes/backend/django/drf.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
