重写BaseFilterView和ListView时返回空QuerySet问题(django-filter版本差异)
我之前踩过一模一样的坑!当你同时继承BaseFilterView和ListView时,在django-filter 2.0.0.dev1版本里会出现QuerySet为空的情况,核心原因就是BaseFilterView的实现逻辑发生了关键变更。
版本差异对比
先看旧版本(django-filter==1.0.2)的BaseFilterView实现:
class BaseFilterView(FilterMixin, MultipleObjectMixin, View): def get(self, request, *args, **kwargs): filterset_class = self.get_filterset_class() self.filterset = self.get_filterset(filterset_class) self.object_list = self.filterset.qs context = self.get_context_data(filter=self.filterset, object_list=self.object_list) return self.render_to_response(context)
在1.0.2版本中,BaseFilterView的get方法会主动把过滤后的filterset.qs赋值给self.object_list,而ListView的渲染逻辑直接依赖这个属性,所以两者配合起来毫无问题。
再看2.0.0.dev1版本的BaseFilterView逻辑变更:
这个版本里,BaseFilterView不再主动处理self.object_list的赋值了!它的get方法只负责初始化filterset,而把object_list的获取逻辑完全丢给了MultipleObjectMixin的默认实现——但MultipleObjectMixin的get_object_list只会读取原始的self.queryset,根本不会用到filterset过滤后的结果。这就导致ListView最终要么拿到未经过滤的原始QuerySet,要么如果你的queryset没正确初始化,就会出现空QuerySet的问题。
两种解决方案
方案一:重写get方法,手动关联过滤结果
直接在自定义View里重写get方法,先完成过滤逻辑,再把结果传递给ListView:
class CustomFilterListView(BaseFilterView, ListView): filterset_class = YourFilterSet queryset = YourModel.objects.all() template_name = "your_template.html" def get(self, request, *args, **kwargs): # 先执行BaseFilterView的过滤流程 filterset_class = self.get_filterset_class() self.filterset = self.get_filterset(filterset_class) # 将过滤后的QuerySet赋值给object_list self.object_list = self.filterset.qs # 再调用ListView的get逻辑完成渲染 return super().get(request, *args, **kwargs)
方案二:重写get_queryset方法返回过滤结果
利用ListView依赖get_queryset获取数据的特性,直接返回过滤后的结果:
class CustomFilterListView(BaseFilterView, ListView): filterset_class = YourFilterSet queryset = YourModel.objects.all() template_name = "your_template.html" def get_queryset(self): # 确保filterset已经被初始化 if not hasattr(self, 'filterset'): filterset_class = self.get_filterset_class() self.filterset = self.get_filterset(filterset_class) # 返回过滤后的QuerySet return self.filterset.qs
这两种方案都能解决空QuerySet的问题,我个人更推荐方案二,因为它更贴合Django类视图的设计逻辑。
内容的提问来源于stack exchange,提问作者andilabs

