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

求助:Django ORM能否通过单查询实现用户班次数量统计?

一次查询统计用户班次数量的解决方案

嘿,同为Django老玩家,太懂这种卡一整天的憋屈了!咱们直接来解决这个问题,先假设你的模型结构大概是这样(如果和实际有出入,你可以调整相关字段和关联名称):

from django.contrib.auth.models import AbstractUser
from django.db import models

class User(AbstractUser):
    pass

class Day(models.Model):
    date = models.DateField()
    # 主管与Day的M2M关联,设置related_name方便反向查询
    supervisors = models.ManyToManyField(User, related_name='supervised_days')

class Shift(models.Model):
    day = models.ForeignKey(Day, on_delete=models.CASCADE, related_name='shifts')
    # 人员与Shift的M2M关联
    workers = models.ManyToManyField(User, related_name='worked_shifts')

要在一次查询里统计每位用户的总班次数量(包含作为员工参与的班次、作为主管关联的班次),咱们可以利用Django的annotate结合Count和Q对象实现:

from django.db.models import Count, Q

# 统计每位用户的总班次数量
user_shift_counts = User.objects.annotate(
    total_shifts=Count(
        'worked_shifts',
        distinct=True  # 避免同一班次被重复计数
    ) + Count(
        'supervised_days__shifts',
        distinct=True  # 确保主管关联的班次只统计一次
    )
).values('username', 'total_shifts')

核心逻辑解释:

  • Count('worked_shifts', distinct=True):统计用户作为员工直接参与的Shift数量,加distinct=True是为了防止极端情况下(比如数据异常)同一班次被重复计数。
  • Count('supervised_days__shifts', distinct=True):通过反向关联找到用户主管的所有Day,再关联到这些Day下的所有Shift,统计总数,同样用distinct=True保证每个Shift只被计数一次。
  • 两个Count结果相加,就是用户的总班次数量。

如果你的需求只是统计用户作为员工参与的班次,那简化版代码如下:

user_worker_counts = User.objects.annotate(
    worked_shift_count=Count('worked_shifts', distinct=True)
).values('username', 'worked_shift_count')

要是需要过滤特定时间段的班次,直接在查询前加filter即可,比如统计2024年全年的班次:

from datetime import date

start_date = date(2024, 1, 1)
end_date = date(2024, 12, 31)

filtered_counts = User.objects.annotate(
    total_shifts=Count(
        'worked_shifts',
        filter=Q(worked_shifts__day__date__range=(start_date, end_date)),
        distinct=True
    ) + Count(
        'supervised_days__shifts',
        filter=Q(supervised_days__date__range=(start_date, end_date)),
        distinct=True
    )
).values('username', 'total_shifts')

这样全程用Django ORM就能搞定,完全不用写raw SQL,性能也能得到保障!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:17:00