如果我有一个嵌套的序列化器:
class ChildSerializer(ModelSerializer):
class Meta:
fields = ('c_name', )
model = Child
class ParentSerializer(ModelSerializer):
child = ChildSerializer(many=True, read_only=True)
class Meta:
model = Parent
fields = ('p_name', 'child')
我想访问嵌套序列化器中的上下文,我该怎么做呢?据我所知,上下文没有传递给子进程。
我希望能够实现每个用户对字段的权限模型,为此我覆盖了ModelSerializer的get_fields()方法:
def get_fields(self):
fields = super().get_fields()
....
for f in fields:
if has_rights(self.context['request'].user, f, "read"):
ret_val[f] = fields[f]
....
return ret_val
下面哪一种方法适用于常规序列化器,但是当嵌套的子元素传递给get_fields()时,上下文以及请求和用户都不可用。当序列化器嵌套时,我如何访问上下文?
8条答案
按热度按时间z6psavjg1#
好的,我找到了一个可行的解决方案,我用添加上下文的SerializerMethodField替换了Parent类中的ChildSerializer赋值,然后将其传递给CustomModelSerializer中的get_fields方法:
在我的CustomModelSerializer中:
这看起来工作得很好,当我撤销 Child.c_name 或 Parent.child 上的读取权限时,序列化器中的子字段将被丢弃
bnlyeluc2#
如果你不能改变你的子序列化器的性质,就像@Kirill Cherepanov和@Robin van Leeuwen回答的那样,一个 * 轻量级但不完全集成的 * 解决方案是在
__init__()
函数中手动传递上下文:2eafrhcq3#
您可以使用
serialziers.ListField
来代替,ListField
会自动将上下文传递给它的子节点。yc0p9oo04#
好了,我找到了一个终极解决方案,它可以完全满足我们的要求--将上下文传递给嵌套的序列化程序。要实现这一点,需要重写嵌套的序列化程序的
to_representation(self, instance)
,如下所示:dbf7pr2w5#
我知道这是一个老问题,但我在2019年也有过同样的问题,以下是我的解决方案:
在上面的代码中,我创建了一个序列化器基类,它覆盖了
get_fields()
,并将self._context
传递给任何具有相同基类的子序列化器。然后,我检查查询参数“omit_data”,如果请求,则删除“data”字段。
我希望这对任何仍在寻找答案的人有帮助。
0s0u357o6#
我使用的是
djangorestframework
3.12.xx,上下文会自动传播到嵌套的序列化程序。erhoui1w7#
如果您试图限制子序列化程序字段的查询集,则继续使用
在子序列化程序内部访问父上下文。
像这样:
这个answer引导我通过调试和查看child的get_fields函数中的可用变量来发现这一点。
yzxexxkh8#
我阅读了源代码,我认为没有必要将上下文传递给嵌套字段序列化程序,因为它们可以访问上下文。
调用嵌套字段序列化程序的上下文将返回根上下文。下面是代码,它已经9年没有更改了。
如果你需要一些解释,在这个例子中,考虑字段是
child
。调用child.context
将调用上面提到的属性函数,该函数本身使用self.root
。在这种情况下,根属性函数将被解析为ParentSerializer
。因此调用
child.context
将导致调用parent.context
。