Как сохранить дополнительные данные в сериализаторе Django REST Framework

В данном уроке мы научимся как передавать дополнительные данные в сериализатор перед их сохранением в базе данных.

 

Введение

При использовании обычных форм Django существует общий шаблон, в котором мы сохраняем форму с помощью commit = False, а затем передаем некоторые дополнительные данные экземпляру перед сохранением их в базе данных, например:
 

form = InvoiceForm(request.POST)
if form.is_valid():
    invoice = form.save(commit=False)
    invoice.user = request.user
    invoice.save()

 

Это очень полезно, потому что мы можем сохранить требуемую информацию, используя только один запрос к базе данных, а также позволяет обрабатывать столбцы, не допускающие значения NULL, которые не были определены в форме.

 

Чтобы смоделировать этот шаблон с помощью сериализатора Django REST Framework, вы можете сделать что-то вроде этого:

serializer = InvoiceSerializer(data=request.data)
if serializer.is_valid():
    serializer.save(user=request.user)

 

Вы также можете передать сразу несколько параметров:

serializer = InvoiceSerializer(data=request.data)
if serializer.is_valid():
    serializer.save(user=request.user, date=timezone.now(), status='sent')

 

Пример использования с APIView

В этом примере я создал приложение с именем core.

 

models.py

from django.contrib.auth.models import User
from django.db import models

class Invoice(models.Model):
    SENT = 1
    PAID = 2
    VOID = 3
    STATUS_CHOICES = (
        (SENT, 'sent'),
        (PAID, 'paid'),
        (VOID, 'void'),
    )

    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='invoices')
    number = models.CharField(max_length=30)
    date = models.DateTimeField(auto_now_add=True)
    status = models.PositiveSmallIntegerField(choices=STATUS_CHOICES)
    amount = models.DecimalField(max_digits=10, decimal_places=2)

 

serializers.py

from rest_framework import serializers
from core.models import Invoice

class InvoiceSerializer(serializers.ModelSerializer):
    class Meta:
        model = Invoice
        fields = ('number', 'amount')

 

views.py

from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
from core.models import Invoice
from core.serializers import InvoiceSerializer

class InvoiceAPIView(APIView):
    def post(self, request):
        serializer = InvoiceSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save(user=request.user, status=Invoice.SENT)
        return Response(status=status.HTTP_201_CREATED)

 

Пример использования с ViewSet

Очень похожий пример с теми же моделями.py и serializers.py, что и в предыдущем примере.

 

views.py

from rest_framework.viewsets import ModelViewSet
from core.models import Invoice
from core.serializers import InvoiceSerializer

class InvoiceViewSet(ModelViewSet):
    queryset = Invoice.objects.all()
    serializer_class = InvoiceSerializer

    def perform_create(self, serializer):
        serializer.save(user=self.request.user, status=Invoice.SENT)