首页 > 解决方案 > Django - 如何在调度方法中访问过滤的查询集?

问题描述

我有以下代码:

class MyViewSet(ModelViewSet):
    ...
    filter_backends = (...)

    def dispatch(self, request, *args, **kwargs):
        response = super(MyViewSet, self).dispatch(
            request,
            *args,
            **kwargs
        )
        ... # do something with the response
        return response

在 dispatch 方法中,我可以使用 检索过滤后的数据response.data,因此我假设自定义过滤器后端工作正常。count()但是,在将过滤器应用于查询集之后,我也想对查询集做一些事情(例如 call )。问题在于self.querysetself.get_queryset()返回整个未过滤的查询集。

那么,如果可能的话,如何获取在调度方法中应用了过滤器的查询集版本呢?

标签: pythondjango

解决方案


您可以使用该filter_queryset方法。它将使用正在使用的过滤器后端对其进行过滤。请参阅其在GenericAPIView课堂上的定义。

def filter_queryset(self, queryset):
    """
    Given a queryset, filter it with whichever filter backend is in use.
    You are unlikely to want to override this method, although you may need
    to call it either from a list view, or from a custom `get_object`
    method if you want to apply the configured filtering backend to the
    default queryset.
    """
    for backend in list(self.filter_backends):
        queryset = backend().filter_queryset(self.request, queryset, self)
    return queryset

因此,您可以过滤查询集,例如,

filtered_queryset = self.filter_queryset(self.get_queryset())
# Then do something with the filtered queryset

请注意,self.filter_queryset(self.get_queryset())即使在以下super调用期间已经过滤了查询集,也会再次过滤查询集

super(MyViewSet, self).filter_queryset(
                                self.queryset()
                                ).

以下是克服重复过滤器调用的一种方法。您可以覆盖该filter_queryset方法并将过滤后的查询集附加到实例。(请注意,此解决方案未经测试

即,像这样的东西。

class MyViewSet(ModelViewSet):
    ...
    filter_backends = (...)

    def dispatch(self, request, *args, **kwargs):
        response = super(MyViewSet, self).dispatch(
            request,
            *args,
            **kwargs
        )
        ... # do something with the response
        # After this super call `_filtered_query_set` attribute will be set.
        # so use `self._filtered_query_set` wherever needed
        return response

   def filter_queryset(self, queryset):
       filtered_query_set = super(MyViewSet, self).filter_queryset(
                            self.queryset()
                            )
       self._filtered_query_set = filtered_query_set
       return filtered_query_set

推荐阅读