序列化器上的 Django Rest Framework 条件字段
Posted
技术标签:
【中文标题】序列化器上的 Django Rest Framework 条件字段【英文标题】:Django Rest Framework Conditional Field on Serializer 【发布时间】:2015-01-14 16:32:09 【问题描述】:我有一个引用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 产生“条件字段”来实现这种效果?
【问题讨论】:
【参考方案1】:没有一个答案能真正回答问题。
简单的做法是默认添加所有字段,然后根据您的条件在初始化序列化程序时将其删除。
在下面的示例中,我们在列出用户时不返回电子邮件。
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)
【讨论】:
这不适用于在ListAPIView
s 中使用的QuerySet
s。
@ErdinEray 可以尝试使用 ViewSet。 ViewSets
和 *View
很容易混合,但它们的界面却截然不同
抱歉,我无法编辑我的评论,所以我想添加一些其他内容。我想访问__init__
上的instance
参数,因为我想根据模型实例上的某些属性有条件地删除一些字段。在这种情况下(访问instance
),它在ListAPIView
中不起作用。您的示例访问context
,这完全没问题,可以在ListAPIView
s 中使用。
@ErdinEray 我对你的意思有点困惑。我的示例适用于视图集(尚未使用“api 视图”进行测试)。因此,只需确保您的类视图继承视图集而不是“api 视图”。它应该工作【参考方案2】:
使用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
【讨论】:
如果没有值,是否会从结果中“移除”条件字段? @GhislainLeveque,SerializeMethodField
是一个只读字段,这意味着它仅在将模型序列化为 JSON 时出现。从 JSON 反序列化到实例时,不能为其赋值。
@GhislainLeveque 不,它仍然会被包括在内。我不确定这个答案是否能解决问题。
@th0th,问题是根据某些条件要求包含该字段。
@th0th,是的。无论从函数返回什么都将在结果中。如果你想删除它,如果它是无,然后谷歌“DRF 动态序列化字段”。【参考方案3】:
推荐的方法是创建自定义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()
【讨论】:
以上是关于序列化器上的 Django Rest Framework 条件字段的主要内容,如果未能解决你的问题,请参考以下文章
django-rest-swagger 是不是不适用于模型序列化器?