Django-Rest-Framework: How to add a calculated field into the serializer (using SerializerMethodField)

The goal is to add an extra field into the model serializer, which is calculated based on a field of the model.

Consider the `Product` model as below.

from django.db import models


class Product(models.Model):
    name = models.CharField(max_length=50)
    price = models.DecimalField(max_digits=5, decimal_places=2)

    def get_discounted_price(self, percent):
        return "%.2f" % (float(self.price) * (1 - percent / 100))

    def __str__(self):
        return self.name

Note that we have a method named `get_discounted_price`, which calculated the discount and returns a new sale price, after applying the discount.

And we want to add a new field into the serializer called sale_price which shows the sale price.

Consider the ProductSerializer serializer as below.

from rest_framework import serializers
from .models import Product


class ProductSerializer(serializers.ModelSerializer):
    sale_price = serializers.SerializerMethodField(read_only=True)

    class Meta:
        model = Product
        fields = ["name", "price", "sale_price"]

    def get_sale_price(self, obj):
        return obj.get_discounted_price(5)

In fields we are adding a new field called sale_price which is not an attribute in our model, so we need to define it as an attribute of the serializer.

So, sale_price is defined as a SerializerMethodField in our serializer, which by-default calls get_sale_price method (get_<field_name>).

get_sale_price method gets the instance as an argument (which is a model instance), and then use the model instance method to calculate the discounted price.

Finally, we have the following view (list_view), which returns the list of products.

from rest_framework.decorators import api_view
from rest_framework.response import Response
from .models import Product
from .serializers import ProductSerializer


@api_view(["GET"])
def list_view(request):
    products = Product.objects.all()
    data = ProductSerializer(products, many=True).data
    return Response(data)

Add this view into the `urls.py`, and see the results into the browser (or using Postman).

Seeing the API response in the browser

That's all! You have a field sale_price in API response, coming through the serializer.

Thank you very much for reading!

Did you find this article valuable?

Support nirmites by becoming a sponsor. Any amount is appreciated!