DRF: Сериализатор для разнородного списка родственных моделей - PullRequest
0 голосов
/ 20 февраля 2019

Грубо говоря, у меня есть следующая схема в ORM:

class Page(models.Model):

    title = models.CharField(max_length=255, null=False, blank=False)

    @property
    def content(self):
        return [Video.objects.all()[0], Text.objects.all()[0], Video.objects.all()[1]]

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

class ContentSerializer(serializers.ListSerializer):

    class Meta:
        model = ???
        fields = '???'


class PageDetailSerializer(serializers.ModelSerializer):
    content = ContentSerializer(many=True)

    class Meta:
        model = Page
        fields = ('title', 'content', )

Итак, я 'Я ищу способ сериализации этого свойства Page.content, а именно:

  1. списка;
  2. будет содержать разнородные данные (например, комбинация Video, Audio, Text и другие модели.

Так что мне нужно как-то исправить один из встроенных сериализаторов, чтобы пройтись по списку и проверить тип каждого объекта. И затем решить, как сериализовать каждый из них. Например, ямог подготовить вид динамически создаваемого ModelSerializer с:

obj_type = type(obj)

class ContentModelSerializer(serializers.ModelSerializer):

    class Meta:
        model = obj_type
        fields = '__all__'

serialized_obj = ContentModelSerializer(obj)

Как я мог это реализовать?

Ответы [ 2 ]

0 голосов
/ 21 февраля 2019

Я много гуглил, прежде чем нашел решение. Эта статья содержит ссылку на SerializerMethodField, которая позволяет вам добавлять пользовательский обработчик для поля.И последнее решение, которое сработало для меня:

class PageDetailSerializer(serializers.ModelSerializer):
    _cache_serializers = {}

    content = serializers.SerializerMethodField()

    class Meta:
        model = Page
        fields = ('title', 'content', )

    def _get_content_item_serializer(self, content_item_type):
        if content_item_type not in self._cache_serializers:
            class ContentItemSerializer(serializers.ModelSerializer):
                class Meta:
                    model = content_item_type
                    exclude = ('id', 'page', )
            self._cache_serializers[content_item_type] = ContentItemSerializer
        return self._cache_serializers[content_item_type]

    def get_content(self, page):
        return [
            self._get_content_item_serializer(type(content_item))(content_item).data for content_item in page.content
        ]
0 голосов
/ 20 февраля 2019

Вы можете просто добиться этого, переопределив to_representation метод Page сериализатора.как это:

class PageDetailSerializer(serializers.ModelSerializer):

class Meta:
    model = Page
    fields = ('title', 'content', )

def to_representation(self, instance):
    ctx = super(PageDetailSerializer, self).to_representation(instance)
    content = instance.content         # property field of page, will return list of items
    serialized_content = []
    for c in content:
        if type(c) == Video:
            serialized_content.append({... serialized data of video type ..})
        elif type(c) == ...
            # other conditions here..
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...