Django如何同时过滤PipelineColumn及关联Sale子级的查询结果
解决方案
Django ORM 对主表做的关联字段过滤,只会限制主表返回的结果范围,不会自动过滤prefetch_related拉取的关联数据,需要手动定义预取的查询条件即可实现需求。
具体实现步骤
1. 导入必要依赖
from django.db.models import Prefetch, Q
2. 修改ViewSet的get_queryset方法
调整逻辑,在读取到优先级过滤参数时,同时对主表过滤、预取的Sale数据过滤、聚合统计的范围做过滤:
def get_queryset(self): # 读取请求中的优先级过滤参数 priority = self.request.query_params.get('priority') # 构建基础Sale过滤条件 sale_filter = Q() if priority is not None: try: priority = int(priority) sale_filter = Q(sale_column__priority=priority) except ValueError: # 参数格式错误时不做过滤 priority = None # 计算总营收,需要同步应用过滤条件 total = PipelineColumn.objects.aggregate( total=Sum("sale_column__expected_income", filter=sale_filter) )["total"] or 0 # 构建查询集 queryset = PipelineColumn.objects.all() # 主表过滤:仅保留存在对应优先级Sale的列 if priority is not None: queryset = queryset.filter(sale_column__priority=priority) # 预取关联Sale,应用过滤条件 if priority is not None: filtered_sale_qs = Sale.objects.filter(priority=priority) queryset = queryset.prefetch_related(Prefetch('sale_column', queryset=filtered_sale_qs)) else: queryset = queryset.prefetch_related('sale_column') # 聚合计算同步应用过滤条件 return queryset.annotate( total_ca=Sum("sale_column__expected_income", filter=sale_filter), percentage_ca=Sum("sale_column__expected_income", filter=sale_filter) * 100 / total if total > 0 else 0 ).order_by("order")
3. (可选)添加优先级参数到过滤字段
如果你用django-url-filter需要注册该参数,可以在filter_fields中添加关联字段:
filter_fields = ["is_done", "sale_column", "sale_column__priority"]
之后直接通过接口url传参?sale_column__priority=2即可触发过滤,和上面的get_queryset逻辑配合即可拿到符合要求的结果。
效果验证
请求接口携带priority=2参数时:
- 仅返回包含优先级为2的Sale的PipelineColumn列
- 每列下的
sale_column列表仅包含优先级为2的Sale卡片 - 列对应的
total_ca、percentage_ca统计值仅计算优先级为2的Sale数据,和看板展示的数据完全匹配。
内容的提问来源于stack exchange,提问作者darkvodka
相关产品推荐
相关产品推荐

