Django Rest Framework Foreign Key in Junction Table

66 Views Asked by At

I have the following model structure:

game | id | name | description | |:-- |:---- |:----------- |

platform | id | name | |:-- |:---- |

game_detail | id | release_date | |:-- |:------------ |

game_platform | id | game_id | platform_id | game_detail_id | |:-- |:------- |:----------- |:-------------- |

game_platform table is the junction table and in which the game_detail_id is foreign key of the game_detail table. Following is the models.py file:

class Game(models.Model):
name = models.CharField(max_length=50)
description = models.TextField(blank=True, null=True)
genre = models.ForeignKey(Genre, related_name="games", on_delete=models.CASCADE)
platforms = models.ManyToManyField(
    "Platform", related_name="games", through="GamePlatform"
)

class Platform(models.Model):
    name = models.CharField(max_length=50)

class GameDetail(models.Model):
    release_date = models.DateField()

class GamePlatform(models.Model):
    game = models.ForeignKey(Game, on_delete=models.CASCADE)
    platform = models.ForeignKey(Platform, on_delete=models.CASCADE)
    game_detail = models.ForeignKey(GameDetail, on_delete=models.CASCADE)

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=["game", "platform"], name="unique_game_platform"
            )
        ]

How do I serialize in serializers.py and write the logic in modelviewset so that I can get something like this as the game api response:

[
    {
        "id": 33,
        "name": "Crysis Remastered",
        "description": "",
        "genre": {
            "id": 1,
            "name": "Fps"
        },
        "platforms": [
            {
             "id": 1,
             "name": "PS5",
             "game_detail": {
              "release_date": "2020-11-03"
             }
            },
            {
             "id": 2,
             "name": "PC",
             "game_detail": {
              "release_date": "2020-11-13"
             }
            }
        ]
    }
]
2

There are 2 best solutions below

0
Manzeer Fasaludeen On

The below code will give you the exact response.

models.py

class GamePlatform(models.Model):
    game = models.ForeignKey(Game, on_delete=models.CASCADE, related_name="game_platforms")
    platform = models.ForeignKey(Platform, on_delete=models.CASCADE)
    game_detail = models.ForeignKey(GameDetail, on_delete=models.CASCADE)

views.py

class GameModelViewSet(ModelViewSet):
    permission_classes = (permissions.AllowAny, )
    serializer_class = GameSerializer
    queryset = Game.objects.all().prefetch_related('game_platforms')

serializers.py

class GameSerializer(serializers.ModelSerializer):
    platforms = serializers.SerializerMethodField()

    class Meta:
        model = Game
        fields = '__all__'
        depth = 1

    def get_platforms(self, obj):
        platforms = GamePlatform.objects.filter(game=obj).values('id', 'platform__name', 'game_detail__release_date')
        final_data = {}
        for platform in platforms:
            final_data['id'] = platform['id']
            final_data['name'] = platform['platform__name']
            final_data['game_detail'] = {
                'release_date': platform['game_detail__release_date']
            }
        return final_data
0
Abdelrhman Hosny On

I guess You will have to create some serializers to get the response you want First, we will create a serializer for Genre model

Class GenreSerializer(serializers.ModelSerializer):
      class Meta:
        model=Genre
        fields =('id','name')

Second a serializer for GameDetail model

Class GameDetailSerializer(serializers.ModelSerializer):
      class Meta:
        model=GameDetail
        fields =('release_date')

Third a serializer for GamePlatform model

Class GamePlatformSerializer(serializers.ModelSerializer):
      game_detail=GameDetailSerializer(read_only=True)
      class Meta:
        model=GamePlatform
        fields =('id','name','game_detail')

The final piece is the serializer for Game model

Class GameSerializer(serializers.ModelSerializer):
      genre=GenreSerializer(read_only=True)
      platforms=GamePlatformSerializer(read_only=True,many=True)
      class Meta:
        model=Game
        fields =('id','name','description','genre','platforms')