标题可能有点混乱。 最好有一个通用的filter
方法,每次检索查询集并应用字段过滤时都会调用该方法。 是的,我可以覆盖qs
属性,首先获得过滤的查询集,然后应用预取。 但是_不清楚这是否会产生一些副作用,传递给过滤器的数据是否可以安全访问。_
这是我的用例。
我正在通过 M2M 关系过滤查询集(如queryset.filter(items__field="foo")
)。 但是,我也想获得由该字段过滤的预取项目。
换句话说,我的过滤器看起来像这样:
# In my filterset
def filter_items_by_field(self, queryset, name, value):
queryset = queryset.all().filter(
items__field=value,
)
prefetched_items = Prefetch(
'items',
Item.objects..filter(
field=value,
),
)
return queryset.prefetch_related(prefetched_items)
# In my vieset
def get_queryset(self):
queryset = super().get_queryset()
# This should be applied everytime
prefetched_items = Prefetch(
'items',
Item.objects..filter(
another_field=some_value,
),
)
return queryset.prefetch_related(prefetched_items)
像这样的单个过滤器按预期工作。 但是,我可能有几个filter_items_by_*
过滤器 + 我需要对所有过滤器的预取查询集应用相同的过滤。 并且多个过滤器不是问题,因为在我的情况下它们是相互排斥的。 但是过滤器+泛型会导致异常。
关键是我只能为同一个查找应用一个预取。 所以,就我而言,我只会得到一个例外。
我有一个临时解决这个问题的方法:所有filter_items_by_*
对预取执行强制过滤。
而在filter_queryset
(应用过滤后),如果items
没有被预取(这是不好的,因为我正在检查受查询集保护的属性),我将预取与强制过滤一起应用。 但是应该有更好的方法来处理这样的情况。
我希望我的例子足够清楚。
嗨@Alexx-G。 我认为这可以通过过滤器集和相关过滤器类之间的一些协调来实现。 本质上,过滤器会将Prefetch
实例附加到其parent
过滤器集。 FilterSet.qs
然后会在适当的时候简单地调用prefetch_related
。
也就是说,这个用例是什么? 我认为可能有更合适的地方来处理预取。
我认为这可以通过过滤器集和相关过滤器类之间的一些协调来实现。
我已经通过覆盖qs
属性解决了我的问题,但同样,这并不明显,也没有记录。 换句话说,我不能确定基类中的一些内部更改不会影响我的过滤器集(好吧,我已经固定了版本,但无论如何......)
也就是说,这个用例是什么? 我认为可能有更合适的地方来处理预取。
我相信我在上面描述了我的用例。 将过滤和预取分开是没有意义的,因为预取依赖于过滤器。 如果我将它们分开,我将不得不对过滤器进行相同的检查。
换句话说,如果有 qs 属性的公共契约的描述或它的文档挂钩,这将改进过滤器集的定制。
嗨@Alexx-G。 2.0 版本仍然是一个出路,但 API 将会有一些变化专门解决这个问题。 简而言之,
.filter_queryset()
方法。 .qs
属性将主要负责调用.filter_queryset()
并缓存其结果。self.form.cleaned_data
获取用于预取的过滤器值。非常感谢您的努力!
最有用的评论
嗨@Alexx-G。 2.0 版本仍然是一个出路,但 API 将会有一些变化专门解决这个问题。 简而言之,
.filter_queryset()
方法。.qs
属性将主要负责调用.filter_queryset()
并缓存其结果。self.form.cleaned_data
获取用于预取的过滤器值。