重用现有的Django rest框架序列化器。

问题描述 投票:0回答:2

我目前正在使用Django Rest Framework,我正在寻找一种方法来重用已经定义好的Serializer的一些属性。为了解释,我将公开一些相关的序列化器。

完成的序列化器:

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)

正如你可以注意到上面,这些序列化器几乎是一样的,但其中一个是对象的简化版本,因为我不想在某些部分检索不必要的信息。这里的问题是,在这种情况下,我们有一个方法序列化器,需要维护两次。也许在未来,我还想添加另一个字段,我需要把它添加到两个字段中。那么,如何实现一个Based Serializer,其中所有的字段都被包含在内,但我可以重用它并从中提取特定的字段?

我已经想好了这些方案:1.使用Base Serializer instance: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

用这种方法,我不知道是否是个好主意,或者说是否可行

  1. 使用SerializerFieldDraft。
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_不是Product实例的属性,因此失败了,我不知道如何实现。

对于这种情况,您有什么建议?任何建议都将被感激。

谢谢!我目前使用的是Django Restrection。

django rest django-rest-framework serializer
2个回答
1
投票

你可以子类简单的一个和添加字段在完整的一个。

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
投票

你可以为序列化器类创建mixin,它可以让你指定哪些字段将在序列化器中被 "使用",其他的将被忽略。

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"))
© www.soinside.com 2019 - 2024. All rights reserved.