You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何优雅重构Django中重复的QuerySet过滤逻辑?

解决Django中重复QuerySet过滤逻辑的通用化方案

针对你遇到的singer/writer模型过滤逻辑高度重复的问题,核心思路是把**可变的部分(主模型、关联周时间表)**抽离出来,将通用过滤逻辑封装成可复用单元,下面给出两种实用的实现方式:

方式一:封装通用私有方法

把重复的过滤逻辑写到一个私有方法中,通过传入不同的模型参数实现复用:

原重复代码示例(模拟)

from .models import singer, writer, weeklyTimeSinger, weeklyTimeWriter

class Filters:
    def queryFilter_singer(self, request):
        queryset = singer.objects.all()
        # 通用过滤逻辑1:按起始日期过滤
        start_date = request.GET.get('start_date')
        if start_date:
            queryset = queryset.filter(weeklytimesinger__date__gte=start_date)
        # 通用过滤逻辑2:按结束日期过滤
        end_date = request.GET.get('end_date')
        if end_date:
            queryset = queryset.filter(weeklytimesinger__date__lte=end_date)
        # 更多重复的过滤逻辑...
        return queryset

    def queryFilter_writer(self, request):
        queryset = writer.objects.all()
        # 和上面完全一致的过滤逻辑,仅关联表名不同
        start_date = request.GET.get('start_date')
        if start_date:
            queryset = queryset.filter(weeklytimewriter__date__gte=start_date)
        end_date = request.GET.get('end_date')
        if end_date:
            queryset = queryset.filter(weeklytimewriter__date__lte=end_date)
        # 更多重复的过滤逻辑...
        return queryset

改写后的代码

from .models import singer, writer, weeklyTimeSinger, weeklyTimeWriter

class Filters:
    def _generic_query_filter(self, main_model, weekly_time_model, request, related_field=None):
        queryset = main_model.objects.all()
        # 自动生成关联字段名,若字段名不同可手动传参覆盖
        related_field = related_field or weekly_time_model.__name__.lower()
        
        # 通用过滤逻辑:统一维护,修改只需改这里
        start_date = request.GET.get('start_date')
        if start_date:
            queryset = queryset.filter(**{f"{related_field}__date__gte": start_date})
        
        end_date = request.GET.get('end_date')
        if end_date:
            queryset = queryset.filter(**{f"{related_field}__date__lte": end_date})
        
        # 其他所有通用过滤逻辑...
        return queryset

    # 对外暴露的方法,只需传入对应模型
    def queryFilter_singer(self, request):
        return self._generic_query_filter(singer, weeklyTimeSinger, request)

    def queryFilter_writer(self, request):
        return self._generic_query_filter(writer, weeklyTimeWriter, request)

方式二:使用Mixin基类(适合后续扩展更多同类模型)

如果后续可能新增类似的模型(比如actor+weeklyTimeActor),用Mixin基类的方式更便于扩展:

from .models import singer, writer, weeklyTimeSinger, weeklyTimeWriter

class BaseWeeklyFilter:
    # 子类需重写这两个属性
    main_model = None
    weekly_time_model = None
    # 若关联字段名和模型类名小写不一致,可手动指定
    related_field = None

    def queryFilter(self, request):
        if not self.main_model or not self.weekly_time_model:
            raise ValueError("必须设置main_model和weekly_time_model属性")
        
        queryset = self.main_model.objects.all()
        related_field = self.related_field or self.weekly_time_model.__name__.lower()
        
        # 通用过滤逻辑
        start_date = request.GET.get('start_date')
        if start_date:
            queryset = queryset.filter(**{f"{related_field}__date__gte": start_date})
        
        end_date = request.GET.get('end_date')
        if end_date:
            queryset = queryset.filter(**{f"{related_field}__date__lte": end_date})
        
        # 其他通用过滤逻辑...
        return queryset

# 针对不同模型创建子类
class SingerFilter(BaseWeeklyFilter):
    main_model = singer
    weekly_time_model = weeklyTimeSinger
    # 若关联字段不是weeklytimesinger,可手动设置:related_field = "custom_related_name"

class WriterFilter(BaseWeeklyFilter):
    main_model = writer
    weekly_time_model = weeklyTimeWriter

使用示例

在视图中直接实例化子类调用即可:

# 处理歌手过滤
singer_filter = SingerFilter()
singer_queryset = singer_filter.queryFilter(request)

# 处理作者过滤
writer_filter = WriterFilter()
writer_queryset = writer_filter.queryFilter(request)

注意事项

  • 如果关联字段名称和模型类名小写不一致(比如模型是weeklyTimeSinger,但关联字段定义为weekly_time_singer),可以在调用通用方法时手动传入related_field参数,或者在Mixin子类中设置related_field属性。
  • 所有通用过滤逻辑只需在一处维护,后续修改需求时无需重复修改多个方法,完全符合DRY(Don't Repeat Yourself)原则。

内容的提问来源于stack exchange,提问作者sablam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 09:05:36