Python

Сохранение данных через сериализатор Django REST Framework

Spread the love

Очень часто приходится сталкиваться с проектами в которых DRF Serializer используется только для вывода данных. А для ввода данных и их верификации используются какие то отдельные функции. Что как мне кажется совершенно неправильно. Если в проекте используется DRF Serializer то именно он и должен быть задействован для ввода и для вывода.

С помощью DRF Serializer можно:

  • вывести сериализованные данные
  • проверить входные данные но не сохранять (например аутентифицировать пользователя)
  • обработать входные данные и сохранить их в базе

С выводом данных, вообще то все понятно. В этой статье я просто хочу напомнить как можно сохранять полученные данные. Более подробно естественно описано в документации.

При использовании обычных форм 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

Очень похожий пример с теми же models.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)

У сериалайзера есть два метода базовых сохранения данных create, update, которые можно использовать для привязки соответствующего функционала:

from rest_framework import serializers
from core.models import Invoice

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

    def create(self, validated_data):
        return Comment(**validated_data)

    def update(self, instance, validated_data):
        instance.number = validated_data.get('number', instance.number)
        instance.date = validated_data.get('date', instance.date)
        return instance

Так же естественно можно переопределить метод save:

from rest_framework import serializers
from core.models import Invoice

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

В целом у DRF очень большое количество настроек и возможностей по управлению данными, поэтому всем рекомендую использовать его не только для вывода информации но для сохранения.

Была ли вам полезна эта статья?
[17 / 3]

Spread the love
DenSP

View Comments

Recent Posts

Vue 3.4 Новая механика v-model компонента

Краткий перевод: https://vuejs.org/guide/components/v-model.html Основное использование​ v-model используется для реализации двусторонней привязки в компоненте. Начиная с Vue…

11 месяцев ago

Анонс Vue 3.4

Сегодня мы рады объявить о выпуске Vue 3.4 «🏀 Slam Dunk»! Этот выпуск включает в…

11 месяцев ago

Как принудительно пере-отобразить (re-render) компонент Vue

Vue.js — это универсальный и адаптируемый фреймворк. Благодаря своей отличительной архитектуре и системе реактивности Vue…

2 года ago

Проблемы с установкой сертификата на nginix

Недавно, у меня истек сертификат и пришлось заказывать новый и затем устанавливать на хостинг с…

2 года ago

Введение в JavaScript Temporal API

Каким бы ни было ваше мнение о JavaScript, но всем известно, что работа с датами…

2 года ago

Когда и как выбирать между медиа запросами и контейнерными запросами

Все, кто следит за последними событиями в мире адаптивного дизайна, согласятся, что введение контейнерных запросов…

2 года ago