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

如何用Django TruncMonth实现每月Top5访问量医院统计

解决方法

要实现每个月患者访问量前5的医院统计,你可以按照以下步骤操作:

方法一:先聚合再筛选(Python层面处理前5)

这种方法先统计所有医院的月度访问数据,再用Python筛选每个月的前5名,适合数据量不大的场景:

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

def get_monthly_top_hospitals():
    # 1. 统计每个医院每月的患者访问量
    monthly_stats = Patient.objects.filter(hospital__isnull=False)  # 排除未关联医院的患者
        .annotate(month=TruncMonth('date_visited'))  # 截断日期到月份
        .values('month', 'hospital__id', 'hospital__name')  # 按月份+医院分组
        .annotate(patient_count=Count('id'))  # 统计患者数量
        .order_by('month', '-patient_count')  # 按月份升序、患者数降序排序

    # 2. 整理为每个月对应的前5家医院
    result = {}
    for stat in monthly_stats:
        month = stat['month']
        month_str = month.strftime("%m/%d/%Y")  # 格式化为示例中的日期样式
        if month_str not in result:
            result[month_str] = []
        if len(result[month_str]) < 5:
            result[month_str].append({
                'hospital_name': stat['hospital__name'],
                'patient_count': stat['patient_count']
            })
    return result

方法二:窗口函数筛选(数据库层面处理前5)

如果数据量较大,推荐用窗口函数在数据库直接筛选每个月的前5名,性能更优:

from django.db.models import Count, Window, F
from django.db.models.functions import TruncMonth, RowNumber

def get_monthly_top_hospitals():
    # 1. 用窗口函数给每个月的医院按访问量排名
    ranked_stats = Patient.objects.filter(hospital__isnull=False)
        .annotate(month=TruncMonth('date_visited'))
        .values('month', 'hospital__id', 'hospital__name')
        .annotate(patient_count=Count('id'))
        .annotate(
            row_num=Window(
                expression=RowNumber(),
                partition_by=['month'],  # 按月份分组排名
                order_by=F('patient_count').desc()  # 按患者数降序排名
            )
        )
        .filter(row_num__lte=5)  # 只保留前5名
        .order_by('month', 'row_num')

    # 2. 整理结果格式
    result = {}
    for item in ranked_stats:
        month_str = item['month'].strftime("%m/%d/%Y")
        if month_str not in result:
            result[month_str] = []
        result[month_str].append({
            'hospital_name': item['hospital__name'],
            'patient_count': item['patient_count']
        })
    return result

在视图中使用

你可以在视图中调用上述函数,将结果返回给前端:

返回JSON格式

from django.http import JsonResponse

def monthly_top_hospitals_view(request):
    top_hospitals = get_monthly_top_hospitals()
    return JsonResponse(top_hospitals, safe=False)

渲染模板

如果要在页面展示,将结果传入模板:

from django.shortcuts import render

def monthly_top_hospitals_view(request):
    top_hospitals = get_monthly_top_hospitals()
    return render(request, 'top_hospitals.html', {'top_hospitals': top_hospitals})

模板示例(top_hospitals.html):

{% for month, hospitals in top_hospitals.items %}
    <div>
        <p>月份 : {{ month }}</p>
        {% for hospital in hospitals %}
            <p>{{ hospital.hospital_name }} : {{ hospital.patient_count }}位患者</p>
        {% endfor %}
    </div>
{% endfor %}

注意事项

  • 必须过滤hospital__isnull=False的患者,避免统计未关联医院的记录
  • 用hospital__id参与分组,防止重名医院被错误合并统计
  • TruncMonth返回的是datetime对象,需要用strftime格式化为你需要的日期样式

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 01:20:32