串行器上的Django Rest框架条件字段

时间:2015-01-14 16:32:10

标签: django django-rest-framework

我有一个引用Generic Relation的模型,我希望以详细的方式序列化。

class AType(models.Model):
    foo = CharField()


class BType(models.Model):
    bar = PositiveIntegerField()


class ToSerialize(models.Model):
    scope_limit = models.Q(app_label="app", model="atype") | \
                  models.Q(app_label="app", model="btype")
    content_type = models.ForeignKey(ContentType, limit_choices_to=scope_limit)
    object_id = models.PositiveIntegerField()
    content_object = generic.GenericForeignKey('content_type', 'object_id')

我希望ToSerialize视图集的list方法的JSON看起来像:

[
    {
       "atype": { "id": 1, "foo": "a" }
    },
    {
       "atype": { "id": 2, "foo": "b" }
    },
    {
       "btype": { "id": 1, "bar": "1" }
    },
    {
       "btype": { "id": 2, "bar": "2" }
    }
]

我有没有办法让ToSerialize对象的视图集生成"条件字段"基于将实现此效果的content_type / object_id?

3 个答案:

答案 0 :(得分:5)

使用SerializeMethodField

class YourSerializer(serializers.ModelSerializer):
    your_conditional_field = serializers.SerializerMethodField()

    class Meta:
        model = ToSerialize

    def get_your_conditional_field(self, obj):
        # do your conditional logic here
        # and return appropriate result
        return obj.content_type > obj.object_id

答案 1 :(得分:4)

没有一个答案能真正回答问题。

最简单的方法是默认添加所有字段,然后根据您的条件在序列化程序初始化时将其删除。

在下面的示例中,列出用户时我们不会退回电子邮件。

class UserSerializer():

    fields = ('username', 'email')

    class Meta:
        model = User

    def __init__(self, *args, **kwargs):

        # Don't return emails when listing users
        if kwargs['context']['view'].action == 'list':
            del self.fields['email']

        super().__init__(*args, **kwargs)

答案 2 :(得分:0)

推荐的方法是创建自定义 RelatedField 。检查DRF docs about generic relationships是一个很好的例子。在OP情况下,它看起来像这样:

class ABTypeRelatedField(serializers.RelatedField):

    def to_representation(self, value):
        """
        Serialize objects to a simple textual representation.
        """
        if isinstance(value, AType):
            return 'AType: ' + value.foo
        elif isinstance(value, BType):
            return 'BType: ' + value.bar
        raise Exception('Unexpected type of content_object')


class ToSerializeSerializer(serializers.Serializer):
    content_object = ABTypeRelatedField()