How to Save Extra Data to a Django REST Framework Serializer


In this tutorial you are going to learn how to pass extra data to your serializer, before saving it to the database.

Introduction

When using regular Django forms, there is this common pattern where we save the form with commit=False and then pass some extra data to the instance before saving it to the database, like this:

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

This is very useful because we can save the required information using only one database query and it also make it possible to handle not nullable columns that was not defined in the form.

To simulate this pattern using a Django REST Framework serializer you can do something like this:

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

You can also pass several parameters at once:

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

Example Using APIView

In this example I created an app named 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)

Example Using ViewSet

Very similar example, using the same models.py and serializers.py as in the previous example.

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)