[PYTHON] [Django] Pass the user instance authenticated by API to ModelSerializer

It's a little clogged, so make a note.

environment

About ModelSerializer

In django-rest-framework (hereafter DRF), conversion between Json and Model is performed via an object called ModelSerializer. When editing and registering the value received by API, returning a record that does not exist in the table, processing the data and converting it to Json, a method is often added to Serializer.

Also, in DRF, when token authentication is performed, the user instance is stored in the request object. If you pass a user instance to Serializer, the value of the relation destination can be automatically entered, so there are many usage scenes.

model

The prerequisite Visitor model is as follows.

import uuid
from django.db import models
from api.models import AppUser
from web.models import AdminUser


class Visitor(models.Model):
    class Meta:
        db_table = "visitor"
        verbose_name_plural = 'Visitor'

    uuid = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    parent_user = models.ForeignKey(AdminUser,
                                    on_delete=models.CASCADE,
                                    related_name='visitor')
    name = models.CharField(max_length=50)
    email = models.EmailField(max_length=255, null=True, blank=True)
    company = models.CharField(max_length=50, blank=True, null=True)
    memo = models.TextField(blank=True, null=True, max_length=300)
    visit_count = models.PositiveIntegerField(default=0)
    created_by = models.ForeignKey(AppUser,
                                   on_delete=models.SET_NULL,
                                   null=True, blank=True,
                                   related_name='visitor')
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.name

serializer

The serializer creates fields associated with the model. To change the value arbitrarily, override it with SerializerMethodField (). The field defined by SerializerMethodField () calls the methodget_ <field name>and stores the return value.

The method of get_ <field name> has ʻinstance` as an argument. Therefore, I thought that it would be passed here when API authentication was performed, but it seems that the instance itself created at the time of Creation is passed here. (If you use this, you can automatically create the data of the relation destination.)

from rest_framework.serializers import ModelSerializer, SerializerMethodField

class VisitorCreateSerializer(ModelSerializer):
    created_by = SerializerMethodField()
    parent_user = SerializerMethodField()

    class Meta:
        model = Visitor
        read_only_fields = (
            'pk',
            'created_at',
            'created_by',
        )
        fields = (
            'pk',
            'parent_user',
            'created_at',
            'name',
            'email',
            'company',
            'memo',
            'updated_at',
        )

    def get_created_by(self, instance):
        """The sending user is created_Stored in by"""
        return str(instance.pk)

    def get_parent_user(self, instance):
        """parent_Automatically store user"""
        return str(instance.parent_user.pk)

ViewSet

In View, there is a part that instantiates Serializer, so if you pass user to instance here, it's OK. This time I wanted to separate the serializer only for create, so I overridden the create method and specified the Serializer.

# DRF
from rest_framework import status, viewsets
from rest_framework.permissions import IsAuthenticated
from .serializers import VisitorSerializer, VisitorCreateSerializer
from .models import Visitor
from utils.auth.authentication import APIAuthentication
from rest_framework.response import Response


class VisitorViewSet(viewsets.ModelViewSet):
    serializer_class = VisitorSerializer #Serializer used other than create
    queryset = Visitor.objects.all()

    authentication_classes = (APIAuthentication,)
    permission_classes = (IsAuthenticated,)

    def get_queryset(self):
        #When API authentication is performed,user instance is request.Stored in user.
        admin = self.request.user.parent_user
        qs = Visitor.objects.filter(parent_user=admin)
        return qs

    #Override create method
    def create(self, request, *args, **kwargs):
        #Request to Serializer.If you pass user, get_<field name>Instance is passed to the method
        serializer = VisitorCreateSerializer(instance=request.user, data=request.data)
        #From here on down
        serializer.is_valid(raise_exception=True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

Recommended Posts

[Django] Pass the user instance authenticated by API to ModelSerializer
Pass login user information to view in Django
Allows you to select by name from Django User Name
Pass text to Django genericview
[pepper] Pass the JSON data obtained by python request to the tablet.
Create a REST API to operate dynamodb with the Django REST Framework
Deploy the Django tutorial to IIS ①
How to pass values to JavaScript variables directly from the [Django] template tag
How to check the version of Django
Try to face the integration by parts
I tried to touch the COTOHA API
Output user information etc. to Django log
Try hitting the Spotify API in Django.
Let's create it by applying Protocol Buffer to the API with Serverless Framework.
[Django memo] I want to set the login user information in the form in advance
The format of the message obtained by Slack API is subtly difficult to use
I tried to pass the G test and E qualification by training from 50