1

I am having difficulties in implementing nested serializers in Django REST Framework.
I'm building an Online score board, for which I currently have three models and I'm trying to serialize it into a single response.

models.py

class Player(models.Model):
    first_name = models.CharField(max_length=50)
    last_name = models.CharField(max_length=50)

    def __str__(self):
        return self.first_name


class Event(models.Model):

    user = models.ManyToManyField("Player")
    name = models.CharField(max_length=50)  
    desc = models.CharField(max_length=225)

    def __str__(self):
        return self.name

class LeadBoard(models.Model):
    """model for LeadBoard"""

    player = models.ForeignKey(Player, on_delete=models.CASCADE, related_name='leadboard_player', null=True, blank=True)
    event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name='leadboard_event', null=True, blank=True)
    score = models.IntegerField()

    def __str__(self):
        return self.score

The event model represent some kind of sports events and each Event can have multiple Players (user filed in Event model), the LeadBoard model stores the score of players in each event.

serializer.py

class PlayerSerializer(serializers.ModelSerializer): 

    class Meta:
        model = Player
        fields = ('id','first_name', 'last_name', 'bio')


class EventSerializer(serializers.ModelSerializer):
    
    user = PlayerSerializer(read_only=True, many=True)
    class Meta:
        model = Event
        fields = ('id', 'name', 'user', 'desc')


class LeadBoardSerializer(serializers.ModelSerializer):

    event = EventSerializer(read_only=True)
    
    class Meta:
        model = LeadBoard
        fields = ('id', 'event', 'score')

I have added two Players

         [
            {
                "id": 1,
                "first_name": "Jhon",
                "last_name": "Doe"
            },
            {
                "id": 3,
                "first_name": "Anna",
                "last_name": "Doe"
            }
        ]

and their scores in LeadBoard model

[
    {
        "id": 1,
        "player": 1,
        "event": 1,
        "score": 20
    },
    {
        "id": 2,
        "player": 3,
        "event": 1,
        "score": 90
    }
]

This is the response of LeadBoard,

[
    {
        "id": 1,
        "event": {
            "id": 1,
            "name": "event2020",
            "user": [
                {
                    "id": 1,
                    "first_name": "Jhon",
                    "last_name": "Doe"
                },
                {
                    "id": 3,
                    "first_name": "Anna",
                    "last_name": "Doe"
                }
            ],
            "desc": "event description"
        },
        "score": 20
    },
    {
        "id": 2,
        "event": {
            "id": 1,
            "name": "event2020",
            "user": [
                {
                    "id": 1,
                    "first_name": "Jhon",
                    "last_name": "Doe"
                },
                {
                    "id": 3,
                    "first_name": "Anna",
                    "last_name": "Doe"
                }
            ],
            "desc": "event description"
        },
        "score": 90
    }
]

But what I'm expecting to get is a response like this, which returns the Players(users) of events and their scores correctly.

[
    {
        "id": 1,
        "event": {
            "id": 1,
            "name": "event2020",
            "user": [
                {
                    "id": 1,
                    "first_name": "Jhon",
                    "last_name": "Doe",
                    "score": 20
                },
                {
                    "id": 3,
                    "first_name": "Anna",
                    "last_name": "Doe",
                    "score": 90
                }
            ],
            "desc": "event description"
        }
    }
]

What am I missing here?

I'm new to Django and Django Rest Framework.

3
  • Your LeadBoard model says: one Player, participated one Event and scored Score points. As of now, your LeadBoard response is fine. Since it gives all the players who are listed in LeadBoard, the events they participated and their scores too. Your desired response does not correspond with your models. The "user" array in events serializer gives a list of participants. Since there is no relation between player and scores, why should it give you the score as well? Commented Jan 17, 2020 at 20:04
  • To be more spesific, your LeadBoard model has Foreign Key for both Player and Event models. Then, there is no reason you have a M2M relation between User-Event inside Event model. Since you are bridging them with an M2M relation using LeadBoard model. Commented Jan 17, 2020 at 20:25
  • @engin_ipek thanks for your time, now I understand it more.. I'm entirely new to Django, so can you please brief me what should I do in order to get the expected response. Commented Jan 18, 2020 at 4:42

1 Answer 1

1

You need make response by event not by leadboard.

class PlayerSerializer(serializers.ModelSerializer): 

   class Meta:
        model = Player
        fields = ('id','first_name', 'last_name', 'bio')

class LeadBoardSerializer(serializers.ModelSerializer):

    player = PlayerSerializer(read_only=True)

    class Meta:
        model = LeadBoard
        fields = ('id', 'player', 'score')

class EventSerializer(serializers.ModelSerializer):

    leadboard_event = LeadBoardSerializer(read_only=True, many=True)

    class Meta:
        model = Event
        fields = ('id', 'name', 'desc', 'leadboard_event')

now use view to get event list

Update 1 if you want get score in player.

class PlayerSerializer(serializers.Serializer):  
    player_id = serializers.IntegerField()
    first_name = serializers.CharField(max_length=256)
    last_name = serializers.CharField(max_length=256)
    score = serializers.IntegerField()

class LeadBoardSerializer(serializers.ModelSerializer):

    player = serializers.SerializerMethodField()

    class Meta:
        model = LeadBoard
        fields = ('id', 'player')

    def get_player(self,obj):
        player_dict = {'player_id': obj.player.id, 'first_name': obj.player.first_name, 'last_name': obj.player.last_name, 'score': obj.score}
        result = PlayerSerializer(data=player_dict)
        return result

class EventSerializer(serializers.ModelSerializer):

    leadboard_event = LeadBoardSerializer(read_only=True, many=True)

    class Meta:
        model = Event
        fields = ('id', 'name', 'desc', 'leadboard_event')

Try it.

Sign up to request clarification or add additional context in comments.

7 Comments

Thanks, it works fine and I'm getting somewhat like this, "leadboard_event": [ { "id": 1, "player": { "id": 1, "first_name": "Jhon", "last_name": "Doe", "bio": "heavy" }, "score": 20 }, how can I put the score inside the player instance.
like this, "leadboard_event": [ { "id": 1, "player": { "id": 1, "first_name": "John", "last_name": "Doe", "score": 20 }]
Oh sorry that did't worked, at first it throw an error because of no Meta for PlayerSerializer, it tried adding class Meta: model = Player fields = ('player_id','first_name', 'last_name','score' ) But it throws another error Field name 'player_id' is not valid for model 'Player' .
ohh sorry in PlayerSerializer use serializers.Serializer not serializers.ModelSerializer. Check my update
thanks for your swift response, but it throws another error Got AttributeError when attempting to get a value for field `player_id` on serializer `PlayerSerializer`. The serializer field might be named incorrectly and not match any attribute or key on the `Player` instance. Original exception text was: 'Player' object has no attribute 'player_id'.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.