1

I am trying to add data to my serializer. What I have is a Game model and a Game can have multiple Match models attached to it. The thing is, the Game model doesn't know about this relationship. The relationship is on the Match model as a foreign key to the Game.

However, there are times when I am getting a Game I want to include the Match models with them. Here is my model for a Game:

import uuid
from django.db import models
from django.utils import timezone

class Game(models.Model):
    created_at = models.DateTimeField(editable=False)
    id = models.UUIDField(primary_key=True, default=uuid.uuid4)
    updated_at = models.DateTimeField(editable=False)

    def __str__(self):
        return self.title

    def save(self, *args, **kwargs):
        ''' On save, update timestamps '''
        if not self.created_at:
            self.created_at = timezone.now()
        self.updated_at = timezone.now()
        return super(Analysis, self).save(*args, **kwargs)

    class Meta:
        db_table = "games"

And my Match model:

import uuid
from django.db import models
from django.utils import timezone
from games.models import Game

class Match(models.Model):
    game = models.ForeignKey(Game, on_delete=models.CASCADE)
    created_at = models.DateTimeField(editable=False)
    id = models.UUIDField(primary_key=True, default=uuid.uuid4)
    updated_at = models.DateTimeField(editable=False)

    def save(self, *args, **kwargs):
        ''' On save, update timestamps '''
        if not self.created_at:
            self.created_at = timezone.now()
        self.updated_at = timezone.now()
        return super(Match, self).save(*args, **kwargs)

    class Meta:
        db_table = "matches"

And my GameSerializer:

from rest_framework import serializers
from games.models import Game
from games.serializers import GameSerializer

class GameSerializer(serializers.ModelSerializer):
    class Meta:
        model = Game
        fields = ('id', 'created_at', 'updated_at')

I am assuming that I need to tweak my GameSerializer to make this work correctly and send down the related data. How do I do this?

1 Answer 1

2

You need to add the match field to your GameSerializer, and handle the save yourself.

class GameSerializer(serializers.ModelSerializer):
    matches = MatchSerializer(many=True, source='match_set')

    def save(self):
        matches = self.validated_data.get('matches', [])
        game = super(GameSerializer, self).save()
        for match in matches:
            match['game'] = game
            Match.objects.create(**match)

Add matches to your fields. In the validated_data of the serializer, matches will be a list of validated datas from MatchSerializer. So you can go ahead and create the Match object directly in your GameSerializer save.

Ref: http://www.django-rest-framework.org/api-guide/relations/#writable-nested-serializers

Or if your usecase involves matches sending already existing Match object and you will only need to send the ids in your data, then use this:

class GameSerializer(serializers.ModelSerializer):
    matches = serializers.ListField(
        child=serializers.PrimaryKeyRelatedField(Match))

    def save(self):
        matches = self.validated_data.get('matches')
        game = super(GameSerializer, self).save()
        for match in matches:
            match.game = game
            match.save()
Sign up to request clarification or add additional context in comments.

12 Comments

This doesn't work since matches is not present on the Game model.
@Sethen it is not mandatory that all serializer fields should be present in the model. There can be extra fields in a model serializer that can be used for cases like these
Then why does DRF throw an error when attempting to use your code above?
@Sethen Can you post the traceback?
@Sethen have you overridden the to_representation method of the serializer? If not, try adding source='match_set' to the matches serializer field declaration. Else override to_representation to customize your response
|

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.