Om Kashyap
Om Kashyap

Reputation: 157

How to combine two or more serializers which have custom fields but have same model in Django?

I am trying to create a Serializer Class which have two fields : name , subject but in a case I need to create two different serializers for each of the fields because the NameSerializer and SubjectSerializer will be used in many different places . So if I use them , I can just get detials just via the Serializer and not creating SerializerMethodField every time . For my NameSerializer and SubjectSerializer I am using SerializerMethod field , i am not directly accessing the fields . I am able to get data directly using a single serializer but I am unable to acceess the data when I am using both the serializer under one Combined Serializer.

models.py

class UserAccount(models.Model):
    name = models.CharField(max_length = 200)
    subject = models.CharField(max_length = 200 )

the views.py have serializers as well as the function views views.py

from rest_framework import serializers
from rest_framework.response import Response
from rest_framework.decorators import api_view
from .models import UserAccount

class NameSerializer(serializers.ModelSerializer):
    the_name = serializers.SerializerMethodField("getName")
    class Meta : 
        model = UserAccount
        fields = ["the_name"]
    def getName(self,  object):
        return "__"+str(object.name)+"__"

class SubjectSerializer(serializers.ModelSerializer):
    the_subject = serializers.SerializerMethodField("get_the_subject")
    class Meta :
        model = UserAccount
        fields = ["the_subject"]
    def get_the_subject(self , object) : 
        return "__"+str(object.subject)+"__"

class FullSerializer(serializers.ModelSerializer):
    some_name = NameSerializer()
    some_subject = SubjectSerializer()

    class Meta : 
        model = UserAccount
        fields = ["some_name" , "some_subject"]

@api_view(["GET"])
def theView(request , *args , **kwargs):
    userone = UserAccount.objects.get(id = 1)
    data = FullSerializer(userone).data
    return Response(
        data 
    )

Is there any way to get the data of the same model using two different serializers of same model . Or I am doing something wrong . The two serializers work separately nicely.

The error :

AttributeError: Got AttributeError when attempting to get a value for field `some_name` on serializer `FullSerializer`.
The serializer field might be named incorrectly and not match any attribute or key on the `UserAccount` instance.
Original exception text was: 'UserAccount' object has no attribute 'some_name'.
[16/Sep/2022 12:08:38] "GET / HTTP/1.1" 500 115641

If I run the two serializers separately , they work nicely . But not when used in FullSerializer

Upvotes: 1

Views: 1300

Answers (1)

NKSM
NKSM

Reputation: 5874

You can extend and reuse serializers through inheritance. This allows you to declare a common set of fields or methods on a parent class that can then be used in a number of serializers.

It is also possible to declaratively remove/override a Field inherited from a parent class by setting the name to be None on the subclass.

For you:

class NameSerializer(serializers.ModelSerializer):
    the_name = serializers.SerializerMethodField("getName")

    ...

    def getName(self,  object):
        return "__"+str(object.name)+"__"


class SubjectSerializer(serializers.ModelSerializer):
    the_subject = serializers.SerializerMethodField("get_the_subject")

    ...

    def get_the_subject(self , object) : 
        return "__"+str(object.subject)+"__"


                          ⬇️             ⬇️
class FullSerializer(NameSerializer, SubjectSerializer):
    # To remove parent fields
    the_name = None
    the_subject = None
    # Than you can define your fields
    some_name = serializers.SerializerMethodField("getName")
    some_subject = serializers.SerializerMethodField("get_the_subject")

    class Meta : 
        model = UserAccount
        fields = ["some_name" , "some_subject"]

Upvotes: 6

Related Questions