如何用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
相关产品推荐
相关产品推荐

