Как можно сериализовать (с помощью Django REST API), когда класс несколько раз связан с одним и тем же родовым отношением?

У меня есть класс, который имеет несколько ссылок на один и тот же универсальный класс для различной информации:

class Resort(models.Model):
    id = models.PositiveIntegerField(_('HapNr.'), primary_key=True)
    symbol = models.CharField(_('Kurzzeichen'), max_length=3, blank=True)
    short_description = GenericRelation('MultiLingualText',
                                   verbose_name=_('Beschreibung (ML)'),
                                   related_query_name='resortshortdescriptions')
    long_description = GenericRelation('MultiLingualText',
                                   verbose_name=_('Einleitung (ML)'),
                                   related_query_name='resortlongdescription')

class MultiLingualText(models.Model):
    language = models.ForeignKey(hmodels.LanguageCode, verbose_name=_('Sprache'))
    valid_from = models.DateField(_('Gültig ab'), default=timezone.now)
    text = models.TextField(_('Text'))
    content_type = models.ForeignKey(ContentType, verbose_name=_('Typ'))
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey()
    atu_id = models.CharField(_('ATU Text Id'), max_length=12, editable=False, blank=True)
    atu_context = models.CharField(_('ATU Kontext'), max_length=1, editable=False, blank=True)

Когда мне нужно работать с этим классом с помощью администратора Django, у меня есть два Inline, каждый с набором запросов, выбирающим правильные тексты для этого отношения. Это отлично работает.

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

class ResortSerializer(serializers.HyperlinkedModelSerializer):
    short_description = MultiLingualTextSerializerRSD(many=True, read_only=True)
    long_description = MultiLingualTextSerializerRLD(many=True, read_only=True)

    class Meta:
        model = Resort

class MultiLingualTextSerializerRSD(serializers.HyperlinkedModelSerializer):
    language = serializers.PrimaryKeyRelatedField(read_only=True)

    class Meta:
       model = MultiLingualText

class MultiLingualTextViewSetRSD(viewsets.ModelViewSet):
    serializer_class = MultiLingualTextSerializerRSD
    queryset = MultiLingualText.objects.exclude(atu_id='').order_by('resort', 'content_type', 'object_id',
                                                                '-valid_from')

class ResortViewSet(viewsets.ModelViewSet):
    queryset = Resort.objects.all().order_by('id')
    serializer_class = ResortSerializer
    filter_backends = (filters.DjangoFilterBackend,)
    filter_fields = ('id', 'sihot_nr')

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

Правильная реализация (благодаря @lucasnadalutti)

class ResortSerializer(serializers.HyperlinkedModelSerializer):
    short_description = serializers.SerializerMethodField()
    long_description = serializers.SerializerMethodField()

    def get_short_description(self, obj):
        qs = MultiLingualText.objects.exclude(atu_id='').order_by('-valid_from', 'language__code')
        return MultiLingualTextSerializer(qs, many=True, read_only=True).data

    def get_long_description(self, obj):
        qs = MultiLingualText.objects.filter(atu_id='').order_by('-valid_from', 'language__code')
        return MultiLingualTextSerializer(qs, many=True, read_only=True).data

1 ответ

Решение

MultiLingualTextViewSetRSD не имеет большого смысла в этом контексте, так как вы хотите, чтобы курорты и их описания отправлялись только в одном запросе, как и должно быть. В обычном ForeignKey модель поля отношений, я уверен, что ResortSerializer будет сериализовать только связанные записи, как вы ожидали, но я не уверен, как сериализаторы DRF работают с общими отношениями.

Тем не менее, одним из решений будет заменить:

short_description = MultiLingualTextSerializerRSD(many=True, read_only=True)
long_description = MultiLingualTextSerializerRLD(many=True, read_only=True)

с:

short_description = SerializerMethodField()
long_description = SerializerMethodField()

И реализовать вашу фильтрацию и сериализацию внутри get_short_description а также get_long_description методы. Другое решение состоит в том, чтобы удалить оба атрибута и поместить эту логику в ваш сериализатор to_representation метод.

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