Сериализаторы Django, как показать данные во вложенном сериализаторе bridge model

Я использую Django REST Framework.

У меня есть 3 разные модели, 2 из них - отдельные, а 3-я - bridge model, которая соединяет первые 2 модели

# First standalone model
class Build(TimeStampedModel):
    name = models.CharField(max_length=64, null=False, blank=False)
    type = models.CharField(max_length=64, null=False, blank=False)
    play_as = models.CharField(max_length=64, null=False, blank=False)
    link = models.CharField(max_length=255, null=False, blank=False)

    class Meta:
        ordering = ['-created_at']

    def __str__(self):
        return f'{self.play_as} - {self.name}'


# Second standalone model
class Run(TimeStampedModel):
    name = models.CharField(max_length=64, null=False, blank=False)
    difficulty = models.CharField(max_length=64, null=False, blank=False)
    origin = models.CharField(max_length=64, null=False, blank=False)
    alignment = models.CharField(max_length=64, null=False, blank=False)

    class Meta:
        ordering = ['-created_at']

    def __str__(self):
        return f'{self.name} - {self.difficulty}'
    

# Bridge model
class RunBuild(TimeStampedModel):
    run = models.ForeignKey(
        Run, related_name='runBuild_run', on_delete=models.CASCADE, null=False, blank=False
    )
    build = models.ForeignKey(
        Build, related_name='runBuild_builds', on_delete=models.CASCADE, null=False, blank=False
    )

    class Meta:
        ordering = ['-run']

    def __str__(self):
        return f'{self.run.name} - {self.build.name}'

Сериализатор Build в порядке, проблема стоит в сериализаторах RunBuild и Run.

# Model Serializer for Build model   
class BuildSerializer(serializers.ModelSerializer):
    created_at = serializers.SerializerMethodField()

    class Meta:
        model = Build
        exclude = ['updated_at']

    def get_created_at(self, instance):
        return instance.created_at.strftime('%B %d, %Y')


# Model Serializer for RunBuild model    
class RunBuildSerializer(serializers.ModelSerializer):
    # This doesn't work
    runBuild_builds = BuildSerializer(many=True, read_only=True)
    created_at = serializers.SerializerMethodField()

    class Meta:
        model = RunBuild
        fields = ['run', 'build', 'created_at', 'runBuild_builds']

    def get_created_at(self, instance):
        return instance.created_at.strftime('%B %d, %Y')
    

# Model Serializer for Run model
class RunSerializer(serializers.ModelSerializer):
    # This works
    runBuild_run = RunBuildSerializer(many=True, read_only=True)
    created_at = serializers.SerializerMethodField()

    class Meta:
        model = Run
        fields = [
            'name',
            'difficulty',
            'origin',
            'alignment',
            'created_at',
            'runBuild_run'
        ]

    def get_created_at(self, instance):
        # We will format the date
        return instance.created_at.strftime('%B %d, %Y')

А Run состоит из нескольких полей и множества Builds под ними, поэтому мне понадобилась модель моста. Я могу показать множество RunBuild в сериализаторе Run, например, так

{
    "name": "Versatile Bard",
    "difficulty": "Tactician",
    "origin": "The Dark Urge",
    "alignment": "Chaotic Neutral",
    "created_at": "March 14, 2024",
    "runBuild_run": [
        {
            "run": 1,
            "build": 1,
            "created_at": "March 14, 2024"
        },
        {
            "run": 1,
            "build": 2,
            "created_at": "March 14, 2024"
        },
        ....
    ]
}

Но если я сделаю то же самое для сериализатора RunBuild, он ничего не покажет (а я хочу, чтобы он показывал каждый Build на нем)

{
    "run": 1,
    "build": 1,
    "created_at": "March 14, 2024"
    "runBuild_builds": [
        {
            "name": "Cleric / Bard - CC / Versatile Spellcaster",
            "type": "Main Character",
            "play_as": "Main Character",
            "link": "......."
        },
        ....
    ]
}

Поле runBuild_builds отсутствует в ответе, я добавил его вручную, чтобы показать, как оно должно быть.

В конечном итоге в сериализаторе Run должен получиться результат, подобный этому

{
    "name": "Versatile Bard",
    "difficulty": "Tactician",
    "origin": "The Dark Urge",
    "alignment": "Chaotic Neutral",
    "created_at": "March 14, 2024",
    "runBuild_run": [
        {
            "run": 1,
            "build": 1,
            "created_at": "March 14, 2024",
            "runBuild_builds": [
                {
                    "name": "Cleric / Bard - CC / Versatile Spellcaster",
                    "type": "Main Character",
                    "play_as": "Main Character",
                    "link": "......."
                },
                ....
            ]
        },
        ....
    ]
}

Есть идеи, как изменить мой код?

Обновите свой RunBuildSerializer следующим образом,

class RunBuildSerializer(serializers.ModelSerializer):
# This doesn't work
build = BuildSerializer(many=True, read_only=True)
created_at = serializers.SerializerMethodField()

class Meta:
    model = RunBuild
    fields = ['run', 'build', 'created_at']

def get_created_at(self, instance):
    return instance.created_at.strftime('%B %d, %Y')

Удалите поля runBuild_builds из этого сериализатора. Поскольку это поле related_name, оно должно использоваться, когда нам нужно получить доступ к RunBuild классу из Build класса.

Вернуться на верх