是否可以在序列化器之间创建依赖关系,如下面的代码?
class ProSerializer(serializers.ModelSerializer):
entity = serializers.PrimaryKeyRelatedField(many=False,queryset=Entity.objects.all())
foo = serializers.PrimaryKeyRelatedField(many=True,queryset=Foo.objects.filter(entity=entity))
class Meta:
model = ..............
我想要做的是将Foo上的查询集限制为仅来自所选实体的查询集。有没有办法做到这一点?
答案 0 :(得分:0)
Django Rest Framework不会让这很容易,至少在版本2.x中 - 我不确定是否有任何计划在版本3中做得更好。
我在各个地方修复了这个问题,在序列化程序中尝试捕获,在尝试标准化问题之前,通过数据字典中传递的父属性过滤任何适用的字段的查询集 - 以下是我提出的内容用。
<强> SlugRelatedDependentField 强>
class SlugRelatedDependentField(SlugRelatedField):
def __init__(self, depends_on=None, **kwargs):
assert depends_on is not None, 'The `depends_on` argument is required.'
self.depends_on = depends_on # archive_unit__organization or organization
self.depends_segments = self.depends_on.split('__')
self.depends_parent = self.depends_segments.pop(0)
self.depends_field = SimpleLazyObject(lambda: self.parent.parent.fields[self.depends_parent])
self.depends_queryset = SimpleLazyObject(lambda: self.depends_field.queryset)
self.depends_model = SimpleLazyObject(lambda: self.depends_queryset.model)
super(SlugRelatedDependentField, self).__init__(**kwargs)
def contextualize(self, instance, data):
self.data = data
self.instance = instance
def get_queryset(self):
try:
return self.queryset.filter(**{self.depends_on: reduce(getattr, self.depends_segments, self.get_relation())})
except self.depends_model.DoesNotExist:
# if parent was absent or invalid, empty the queryset
return self.queryset.none()
except TypeError:
# if parent was a Page instance, use the full queryset, it's only a list view
return self.queryset.all()
def get_relation(self):
try:
# if an allowed parent was passed, filter by it
return self.depends_queryset.get(**{self.depends_field.slug_field: self.data[self.depends_parent]})
except (KeyError, TypeError):
# if data was empty or no parent was passed, try and grab it off of the model instance
if isinstance(self.instance, self.parent.parent.Meta.model):
return getattr(self.instance, self.depends_parent)
elif self.instance is None:
raise self.depends_model.DoesNotExist
else:
raise TypeError
<强>用法强>
class RepositorySerializer(ModelSerializer):
organization = SlugRelatedField(queryset=Organization.objects.all(), slug_field='slug')
teams = SlugRelatedDependentField(allow_null=True, depends_on='organization', many=True, queryset=Team.objects.all(), required=False, slug_field='slug')
def __init__(self, instance=None, data=empty, **kwargs):
f = self.fields['teams']
# assign instance and data for get_queryset
f.child_relation.contextualize(instance, data)
# inject relation values from instance if they were omitted so they are validated regardless
if data is not empty and instance and name not in data:
data[name] = [getattr(relation, f.child_relation.slug_field) for relation in getattr(instance, name).all()]
super(RepositorySerializer, self).__init__(instance=instance, data=data, **kwargs)
<强>摘要强>
SlugRelatedDependentField
扩展常规SlugRelatedField
以接受depends_on
kwarg,该kwarg接受描述字段与另一个字段的关系的字符串 - 在此示例中,用法描述了分配到此存储库的团队必须属于该组织。
一些问题
.none()
清空查询集,这可以避免选择泄漏,否则可能会通过OPTIIONS
请求和验证消息泄露,这通常是不受欢迎的。data
,IIRC我之所以这样做是因为data
始终可用,而父字段的对象可能不是例如{I}。在PATCH
请求的情况下。organization
请求中记录的PATCH
,则意味着已分配的teams
不再适用。支持远距离关系
此解决方案适用的另一个问题是引用远程关系,这可以通过将__
分隔的字符串传递给depends_on
来完成,例如: repository__organization
,我没有一个很好的用例,但是如果你需要的话就会有它。