Сохранить pk из подробного маршрута в сериализаторе [django REST API]

Я задавал этот вопрос раньше, но с меньшей ясностью

Как сохранить id внутри RelatedFiled из ForeignKey?

Я тестирую приложение на Django, у меня есть две модели:

class Album(models.Model):
    album_id = models.IntegerField()
    artist = models.CharField(max_length=260)
    album_name = models.CharField(max_length=260)


class Song(models.Model):
    album = models.ForeignKey(Album, related_name='song', blank=True, null=True)    #foreign key
    song_name = models.CharField(max_length=260)

с Song содержащий внешний ключ к Album

Мой вопрос заключается в том, как автоматически хранить pk или же id из album внутри этого внешнего ключа?

Я создал detail_route и когда я печатаю album_id Я получаю правильный адрес, к которому я пытаюсь получить доступ в URL.

например: album/101/song распечатает album_id как 101. Но в моем сериализаторе он не сохраняет RelatedField как 101. Как мне это исправить?

    @detail_route(methods=['post', 'get'], serializer_class=SongSerialiser)
    def get_so(self, request, album_id=None):
        serializer = self.get_serializer(data=request.data, context={"album_id": album_id })
        if serializer.is_valid():
            print album_id # this works !
            serializer.save()
            return Response(serializer.data, status=status.HTTP_200_OK)
        else:
            return Response({"detail": serializer.errors,
                             "status_code": status.HTTP_400_BAD_REQUEST})

Сериализатор:

class SongSerialiser(serializers.Serializer):
    album = serializers.RelatedField(many=True)
    song_name = serializers.CharField(required=False)

    def create(self, validated_data):
        album_id = self.context.get("album_id")
        print album_id   # I expect this to print 101 or the related id
        instance = Song.objects.create(**validated_data)
        instance.save()
        return instance

2 ответа

Решение

Оказывается, внутри сериализатора мне нужно использовать:

self.context.get("request").parser_context["kwargs"]["album_id"]

Вместо прохождения album_id в context, вы можете пройти album_id с помощью serializer.save() и DRF автоматически создаст Song объект с album_id поле.

Вам нужно внести некоторые изменения в свой код.

По вашему мнению, вам не нужно проходить context к сериализатору. Вы должны вместо этого пройти album_id в serializer.save(),

@detail_route(methods=['post', 'get'], serializer_class=SongSerialiser)
def get_so(self, request, album_id=None):
    serializer = self.get_serializer(data=request.data)
    if serializer.is_valid():
        serializer.save(album_id=album_id) # pass album_id here
        return Response(serializer.data, status=status.HTTP_200_OK)
    else:
        return Response({"detail": serializer.errors,
                         "status_code": status.HTTP_400_BAD_REQUEST})

Во-вторых, вы можете конвертировать SongSerialiser в ModelSerializer имея только поле song_name без добавления create() метод.

class SongSerialiser(serializers.ModelSerializer): # use modelserializer

    class Meta:
        model = Song
        fields = ['song_name'] # only define song_name field

когда serializer.save() называется, DRF создаст Song объект с song_name от request.data а также album_id из лишнего kwarg мы прошли в .save(),

Другие вопросы по тегам