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

基于日期范围的Django ORM经理工单统计问题

解决Django ORM中按经理指派时间段统计工单数量的问题

这问题挺常见的——要精准统计指定日期范围内,各经理实际负责期间关闭的工单数量,核心是要把工单产生/关闭时间和客户对应经理的指派时间段严格匹配,不能把跨经理交接的工单算错人。我来一步步拆解实现方案:

第一步:先明确模型结构(假设你的模型如下,可根据实际调整)

首先得确保模型之间的关联逻辑正确,这里给出符合需求的典型模型定义:

from django.db import models

class Manager(models.Model):
    name = models.CharField(max_length=100)
    # 其他经理相关字段,比如工号、部门等

class Customer(models.Model):
    name = models.CharField(max_length=100)
    assignee = models.ForeignKey(Manager, on_delete=models.CASCADE, related_name='customers')
    assignee_start_date = models.DateField()
    assignee_end_date = models.DateField(null=True, blank=True)  # 空值表示当前仍在负责该客户
    # 其他客户相关字段

class Order(models.Model):
    customer = models.ForeignKey(Customer, on_delete=models.CASCADE, related_name='orders')
    # 其他订单相关字段,比如订单编号、金额等

class Ticket(models.Model):
    order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name='tickets')
    ticket_date = models.DateTimeField()  # 这里假设是工单关闭时间,若为创建时间可调整字段名
    status = models.CharField(max_length=20, choices=[('open', '待处理'), ('closed', '已关闭')])
    # 其他工单相关字段,比如问题描述、优先级等

第二步:核心ORM查询实现

重点要处理两个时间匹配逻辑:

  1. 工单的关闭时间在你指定的统计范围内
  2. 工单的关闭时间落在该经理对对应客户的指派时间段内

下面是完整的查询代码,包含了边界情况处理(比如经理当前仍在负责客户,assignee_end_date为空的场景):

from django.db.models import Count, Q, F
from datetime import date

# 定义要统计的日期范围(示例为2024年1月1日至1月31日)
stat_start_date = date(2024, 1, 1)
stat_end_date = date(2024, 1, 31)

# 统计各经理关闭的工单数量
manager_closed_tickets = (
    Manager.objects
    # 过滤条件:工单在统计范围内,且状态为已关闭
    .filter(
        customers__orders__tickets__ticket_date__date__range=(stat_start_date, stat_end_date),
        customers__orders__tickets__status='closed',
        # 关键逻辑:工单关闭时间必须在该经理对客户的指派区间内
        Q(
            customers__assignee_start_date__lte=F('customers__orders__tickets__ticket_date__date')
        ) & (
            Q(customers__assignee_end_date__gte=F('customers__orders__tickets__ticket_date__date')) |
            Q(customers__assignee_end_date__isnull=True)
        )
    )
    # 用distinct=True避免同一工单因多表关联被重复统计
    .annotate(closed_tickets_count=Count('customers__orders__tickets', distinct=True))
    # 指定返回的字段:经理ID、名称、统计数量
    .values('id', 'name', 'closed_tickets_count')
    # 可选:按统计数量降序排序,方便查看排名
    .order_by('-closed_tickets_count')
)

关键细节解释

  • F表达式的作用:用F()动态获取工单的日期,和经理的指派起止日期做数据库层面的实时比较,避免Python层面的日期硬编码,同时保证匹配的精准性。
  • 处理未结束的指派:如果经理当前还在负责该客户,assignee_end_date会为空,这时候只需要判断工单日期晚于等于指派开始日期即可。
  • distinct=True的必要性:因为多表关联(Manager→Customer→Order→Ticket)会产生重复的工单记录,必须加上这个参数确保每个工单只被统计一次。
  • ticket_date__date的用法:如果你的ticket_date是DateTimeField,用__date可以提取日期部分,和统计的日期范围(date类型)做匹配,避免时间精度带来的误差。

场景验证

针对你提到的示例:客户1-10日由M1负责,期间产生2个关闭工单;10日后由M2负责,产生4个关闭工单。用这个查询统计1月1日到1月31日的数据时,M1会得到2,M2得到4,完全符合预期,不会出现跨时间段的错误统计。


内容的提问来源于stack exchange,提问作者Mayank Pratap Singh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:33:05