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

Django如何统计每位医生月度及全时段预约记录并排序

实现思路

基于给出的Django模型结构,通过ORM聚合函数即可完成要求的排序、统计需求,不需要手写原生SQL。
首先附上参考模型(已修正代码转义字符):

class Doctors(models.Model):
    title = models.CharField(max_length=255)
    slug = models.SlugField(max_length=255, unique=True, db_index=True, verbose_name="URL")
    content = models.TextField(blank=True)
    photo = models.ImageField(upload_to="photos/%Y/%m/%d")
    time_create = models.DateTimeField(auto_now_add=True)
    time_update = models.DateTimeField(auto_now=True)
    spec = models.ForeignKey('Speciality', on_delete=models.PROTECT, null=True)


class Appointment(models.Model):
    class Meta:
        unique_together = ('title', 'date', 'timeslot')

    TIMESLOT_LIST = (
        (0, '09:00 - 09:30'),
        (1, '10:00 - 10:30'),
        (2, '11:00 - 11:30'),
        (3, '12:00 - 12:30'),
        (4, '13:00 – 13:30'),
        (5, '14:00 – 14:30'),
        (6, '15:00 – 15:30'),
        (7, '16:00 – 16:30'),
        (8, '17:00 – 17:30'),
    )

    title = models.ForeignKey('Doctors', on_delete=models.CASCADE)
    date = models.DateField()
    timeslot = models.IntegerField(choices=TIMESLOT_LIST)
    username = models.ForeignKey(User, max_length=60, on_delete=models.CASCADE)
    complaints = models.CharField(max_length=500)
    phone = models.CharField(max_length=30)

注意:现有Appointment模型中关联Doctors的外键命名为title存在歧义,该字段实际存储的是医生模型实例,不是职称/名称文本,后续迭代建议迁移改名为doctor提升代码可读性,以下示例暂时沿用现有字段名编写。

1. 统计每位医生全周期预约总记录数

通过annotate配合反向关联的聚合查询即可,一次查询就能给所有医生对象附加总预约数字段:

from django.db.models import Count

# 查询所有医生,附加总预约数属性
doctor_list = Doctors.objects.annotate(
    total_appointment_count = Count('appointment')
)

# 取值示例
# for doc in doctor_list:
#     print(f"医生{doc.title}总预约量:{doc.total_appointment_count}")

2. 月度预约统计+排序

使用TruncMonth函数将预约日期截断到月份维度,分组聚合后即可得到每位医生每月的预约量,支持自定义排序规则:

from django.db.models import Count
from django.db.models.functions import TruncMonth

monthly_stats = Appointment.objects.annotate(
    # 把预约日期截断到月份,格式如2024-06-01
    stat_month = TruncMonth('date')
).values(
    'title_id', # 关联的医生ID
    'title__title', # 医生名称(对应Doctors表的title字段)
    'stat_month'
).annotate(
    monthly_count = Count('id') # 统计该医生当月的预约数
).order_by(
    'title_id', # 优先按医生ID分组排序
    '-stat_month', # 同一医生的记录按月份倒序,最新月份在前
    '-monthly_count' # 如需按月度预约量倒序保留该规则即可,不需要可以删除
)

如果只需要统计指定月份的所有医生预约量,可以加过滤条件:

# 示例:统计2024年6月的医生预约量
june_2024_stats = Appointment.objects.filter(
    date__year=2024,
    date__month=6
).values('title_id', 'title__title').annotate(
    monthly_count = Count('id')
).order_by('-monthly_count') # 按当月预约量从高到低排序

3. 合并统计:一次查询同时返回总预约数、指定月预约数

如果需要在医生列表页同时展示总预约量、当月预约量并排序,可以用子查询避免多次查库:

from django.db.models import Count, OuterRef, Subquery
from datetime import date

# 构造当月预约量子查询
current_month = date.today().month
current_year = date.today().year
current_month_count_subq = Appointment.objects.filter(
    title_id=OuterRef('pk'),
    date__year=current_year,
    date__month=current_month
).values('title_id').annotate(cnt=Count('id')).values('cnt')

# 最终查询结果
doctor_rank_list = Doctors.objects.annotate(
    total_count = Count('appointment'),
    current_month_count = Subquery(current_month_count_subq, default=0) # 当月无预约默认返回0
).order_by('-current_month_count') # 按月度预约量倒序排列

补充说明

  • 排序规则可以根据业务需求调整order_by内的字段:字段名前加-为倒序,不加为正序
  • 如果需要获取单个医生的月度预约明细,只需要在查询时增加title_id=目标医生ID的过滤条件即可
  • 大数据量场景下建议给Appointment表的title、date字段加联合索引,提升统计查询速度

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 01:25:06