Как использовать SlugRelatedField для входящего запроса (десериализация) и полный сериализатор для ответа на связанные поля - PullRequest
0 голосов
/ 03 декабря 2018

Моя модель БД состоит из событий, и каждое событие связано с местом проведения.Когда я получаю список событий, которые я использую:

venue = VenueSerializer(read_only=True)

Когда я отправляю сообщение на мою конечную точку drf, я использую:

venue = serializers.SlugRelatedField(
        allow_null=True,
        queryset=Venue.objects.all(),
        required=False,
        slug_field='id')

Однако это приводит к тому, что в ответе я получаю от сообщениязапрос, место сериализации как поле слаг.Я хочу, чтобы он использовал VenueSerialiser для ответа.

Я получил https://stackoverflow.com/a/49035208/5683904, но он работает только на самом Viewset.

   #serializer_class = EventSerializer
   read_serializer_class = EventSerializer
   create_serializer_class = EventCreateUpdateSerializer

Мне нужно создать эту функциональностьв самом сериализаторе, поскольку он используется совместно с другими компонентами.

1 Ответ

0 голосов
/ 12 декабря 2018

Проблема

Метод to_representation SlugRelatedField кодируется так, чтобы возвращать значение ключевого аргумента slug_field, который вы передаете ему во время инициализации.

Обходные пути

  • Расширьте SlugRelatedField и переопределите его to_representation методом, чтобы вернуть полный объект вместо слага.Это может быть немного сложно, потому что фактический экземпляр модели не является частью класса.

  • Имеют два поля, одно для слаг и другое для фактического объекта.Это проще реализовать.

Вот как вы можете реализовать второй обходной путь:

venue = VenueSerializer(read_only=True)
venue_id = serializers.SlugRelatedField(
        write_only=True
        allow_null=True,
        queryset=Venue.objects.all(),
        required=False,
        slug_field='id')

ОБНОВЛЕНИЕ : Это, по-видимому, довольноРазыскиваемая функция в DRF.Я также нашел способ реализовать первый обходной путь.Он имеет дело с PrimaryKeyRelatedField, но вы, вероятно, можете изменить его для работы с SlugRelatedField.Вот оно:

from collections import OrderedDict

from rest_framework import serializers


class AsymetricRelatedField(serializers.PrimaryKeyRelatedField):

    def to_representation(self, value):
        return self.serializer_class(value).data

    def get_queryset(self):
        if self.queryset:
            return self.queryset
        return self.serializer_class.Meta.model.objects.all()

    def get_choices(self, cutoff=None):
        queryset = self.get_queryset()
        if queryset is None:
            return {}

        if cutoff is not None:
            queryset = queryset[:cutoff]

        return OrderedDict([
            (
                item.pk,
                self.display_value(item)
            )
            for item in queryset
        ])

    def use_pk_only_optimization(self):
        return False

    @classmethod
    def from_serializer(cls, serializer, name=None, args=(), kwargs={}):
        if name is None:
            name = f"{serializer.__class__.name}AsymetricAutoField"

        return type(name, [cls], {"serializer_class": serializer})

Затем вы можете использовать это поле следующим образом:

class FooSerializer(serilizers.ModelSerializer):

    bar = AsymetricRelatedField(BarSerializer)

    class Meta:
        model = Foo

Вы можете найти оригинальное обсуждение этого здесь

...