Django 1.11 Admin实现事件统计及按指定时间排序方案
Django 1.11 Admin 实现需求方案
一、模型优化(可选)
原模型中event字段为TextField,且有固定可选值A/B/C,推荐改为带选项的CharField,避免非法输入:
class Random(models.Model): EVENT_CHOICES = ( ('A', '事件A'), ('B', '事件B'), ('C', '事件C'), ) person = models.TextField(blank=True, null=True) event = models.CharField(max_length=1, choices=EVENT_CHOICES, blank=True, null=True) event_date = models.DateTimeField(blank=True, null=True)
二、Admin核心实现
在admin.py中通过聚合查询和子查询实现需求,具体代码如下:
from django.contrib import admin from django.db.models import Count, Case, When, Subquery, OuterRef, DateTimeField from .models import Random class RandomAdmin(admin.ModelAdmin): # 配置列表显示字段 list_display = ( 'person', 'event_count_A', 'event_count_B', 'event_count_C', 'latest_A_event', ) def get_queryset(self, request): # 子查询:获取每个人员最近一次事件A的时间 latest_a_subquery = Random.objects.filter( person=OuterRef('person'), event='A' ).order_by('-event_date').values('event_date')[:1] # 主查询:筛选参与过A事件的人员,按人员分组统计各事件次数 qs = Random.objects.filter(event='A').values('person').annotate( event_count_A=Count(Case(When(event='A', then=1))), event_count_B=Count(Case(When(event='B', then=1))), event_count_C=Count(Case(When(event='C', then=1))), latest_A_event=Subquery(latest_a_subquery, output_field=DateTimeField()) ).distinct().order_by('-latest_A_event') return qs # 定义各统计字段的显示逻辑 def event_count_A(self, obj): return obj['event_count_A'] event_count_A.short_description = 'event-count-A' def event_count_B(self, obj): return obj['event_count_B'] event_count_B.short_description = 'event-count-B' def event_count_C(self, obj): return obj['event_count_C'] event_count_C.short_description = 'event-count-C' # 格式化最近A事件的日期显示 def latest_A_event(self, obj): return obj['latest_A_event'].strftime('%d %b %Y') if obj['latest_A_event'] else '-' latest_A_event.short_description = 'latest_A_event' admin.site.register(Random, RandomAdmin)
代码说明
- 筛选与分组:通过
filter(event='A')筛选参与过A事件的记录,再用values('person').distinct()得到唯一人员列表,确保按人员分组统计。 - 事件次数统计:使用
annotate结合Case/When和Count函数,分别统计每个人员参与A、B、C事件的次数。 - 最近A事件时间:通过
Subquery子查询获取每个人员最近一次A事件的时间,作为排序依据。 - 排序与显示:按
latest_A_event倒序排列,自定义显示方法格式化日期并设置列名。
内容的提问来源于stack exchange,提问作者Apple-and-Oranges
相关产品推荐
相关产品推荐

