Повторное использование существующего сериализатора Django rest framework - PullRequest
0 голосов
/ 07 мая 2020

В настоящее время я использую Django Rest Framework, и я ищу способ повторно использовать некоторые атрибуты из уже определенного сериализатора. Чтобы объяснить, я собираюсь раскрыть некоторые из задействованных сериализаторов:

Завершенный сериализатор:

class ProductSerializer(serializers.ModelSerializer):
    subscribed = serializers.SerializerMethodField()
    other_field = serializers.SerializerMethodField()

    class Meta:
        model = Product
        fields = [
            'id',
            'name',
            'subscribed',
            'other_field',
            'x',
            'y',
            'z'
        ]

    def get_subscribed(self, product: Product):
        return product.is_user_subscribed(self.context['request'].user)

Упрощенный сериализатор:

class ProductSimplifiedSerializer(serializers.ModelSerializer):
    subscribed = serializers.SerializerMethodField()

    class Meta:
        model = Product
        fields = [
            'id',
            'name',
            'subscribed'
        ]

    def get_subscribed(self, product: Product):
        return product.is_user_subscribed(self.context['request'].user)

Как вы можете заметить выше, эти сериализаторы почти такие же, но один из них является упрощенной версией объекта, потому что я не хочу извлекать ненужную информацию в некоторых частях. Проблема здесь в том, что в этом сценарии у нас есть сериализатор методов, который нужно будет поддерживать два раза. Возможно, в будущем я захочу добавить еще одно поле, и мне нужно будет добавить его в оба. Итак, как можно создать базируемый сериализатор, в который включены все поля, но я мог бы повторно использовать его и извлекать из него определенные c поля?

Я уже думал об этих вариантах: 1. Использование экземпляра базового сериализатора : Draft:

def to_representation(self, instance)
    desired_format = self.context['format']
    if desired_format == 'simplified':
        fields = ['fields_for_simplified']
    elif desired_format == 'regular':
        fields = ['fields_for_regular']

    for field in fields:
        # make the representation

При таком подходе я не знаю, будет ли это хорошая идея или возможно

Использование SerializerField Draft:
class UserSubscribed(serializer.SerializerField)
    def to_representation(self, instance):
        return 'representation'

class ProductSimplifiedSerializer(serializers.ModelSerializer):
    user_subscribed = UserSubscribed()

    class Meta:
        model = Product
        fields = [
            'id',
            'name',
            'user_subscribed'
        ]

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

Что бы вы посоветовали относительно этой ситуации? Любой совет будет оценен.

Спасибо!

Ответы [ 2 ]

1 голос
/ 07 мая 2020

Вы можете создать подкласс простого и добавить поля в полный.

class ProductSimplifiedSerializer(serializers.ModelSerializer):
    subscribed = serializers.SerializerMethodField()

    class Meta:
        model = Product
        fields = [
            'id',
            'name',
            'subscribed'
        ]

    def get_subscribed(self, product: Product):
        return product.is_user_subscribed(self.context['request'].user)


class ProductSerializer(ProductSimplifiedSerializer):
    other_field = serializers.SerializerMethodField()

    class Meta(ProductSimplifiedSerializer.Meta):
        fields = ProductSimplifiedSerializer.Meta.fields + [
            'other_field',
            'x',
            'y',
            'z'
        ]

Хитрость здесь в том, что вы можете создать подкласс и от класса Meta. Любые атрибуты, которые вы определяете в подклассе Meta, будут перезаписывать родительские, поэтому вам придется вручную использовать родительские.

0 голосов
/ 07 мая 2020

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

class DynamicFieldsMixin(object):
    def __init__(self, *args, **kwargs):
        # Don't pass the 'fields' arg up to the superclass
        fields = kwargs.pop('fields', None)

        # Instantiate the superclass normally
        super().__init__(*args, **kwargs)

        if fields is not None:
            # Drop any fields that are not specified in the `fields` argument.
            allowed = set(fields)
            existing = set(self.fields)
            for field_name in existing - allowed:
                self.fields.pop(field_name)

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

class ProductSerializer(DynamicFieldsMixin, serializers.ModelSerializer)

serializer = ProductSerializer(fields=("id", "name", "subscribed"))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...