Django-filter: 允许覆盖 FilterSet 中查询集的检索

创建于 2017-06-21  ·  4评论  ·  资料来源: carltongibson/django-filter

标题可能有点混乱。 最好有一个通用的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。 2.0 版本仍然是一个出路,但 API 将会有一些变化专门解决这个问题。 简而言之,

  • 您将要覆盖.filter_queryset()方法。 .qs属性将主要负责调用.filter_queryset()并缓存其结果。
  • 您可以从self.form.cleaned_data获取用于预取的过滤器值。

所有4条评论

嗨@Alexx-G。 我认为这可以通过过滤器集和相关过滤器类之间的一些协调来实现。 本质上,过滤器会将Prefetch实例附加到其parent过滤器集。 FilterSet.qs然后会在适当的时候简单地调用prefetch_related

也就是说,这个用例是什么? 我认为可能有更合适的地方来处理预取。

我认为这可以通过过滤器集和相关过滤器类之间的一些协调来实现。

我已经通过覆盖qs属性解决了我的问题,但同样,这并不明显,也没有记录。 换句话说,我不能确定基类中的一些内部更改不会影响我的过滤器集(好吧,我已经固定了版本,但无论如何......)

也就是说,这个用例是什么? 我认为可能有更合适的地方来处理预取。

我相信我在上面描述了我的用例。 将过滤和预取分开是没有意义的,因为预取依赖于过滤器。 如果我将它们分开,我将不得不对过滤器进行相同的检查。

换句话说,如果有 qs 属性的公共契约的描述或它的文档挂钩,这将改进过滤器集的定制。

嗨@Alexx-G。 2.0 版本仍然是一个出路,但 API 将会有一些变化专门解决这个问题。 简而言之,

  • 您将要覆盖.filter_queryset()方法。 .qs属性将主要负责调用.filter_queryset()并缓存其结果。
  • 您可以从self.form.cleaned_data获取用于预取的过滤器值。

非常感谢您的努力!

此页面是否有帮助?
0 / 5 - 0 等级