如何通过Django ORM查询计算每个用户的累计登录时长及平均登录时长
计算用户累计/平均登录时长的ORM实现方案
前置说明
你当前的模型存在逻辑缺陷:AllLogin和AllLogout两张表没有关联字段,无法直接匹配某一次登录对应的登出记录。以下方案基于同一个用户同一天的登录、登出记录视为一次登录会话的逻辑实现,如果需要更精准的会话配对,建议先给AllLogout表新增login_record外键关联AllLogin表,每次用户登出时绑定对应登录记录。
具体代码实现
依赖导入
需要提前导入Django ORM相关的工具类:
from django.db.models import F, Sum, Avg, ExpressionWrapper, DurationField from django.db.models.functions import Combine from rest_framework import status
视图函数代码
class ListUsers(generics.GenericAPIView): def get(self,request): # 1. 关联登录登出记录,拼接完整datetime并计算单次会话时长 login_logout_pairs = AllLogin.objects.annotate( # 把分开存储的登录日期、时间拼接为完整datetime login_datetime=Combine('login_date', 'login_time'), # 匹配同用户同日期的登出记录,默认取第一条,可按需调整排序 logout_datetime=AllLogout.objects.filter( user=F('user'), logout_date=F('login_date') ).annotate( full_logout=Combine('logout_date', 'logout_time') ).order_by('logout_time').values('full_logout')[:1] ).annotate( # 计算单次登录的时长 session_duration=ExpressionWrapper( F('logout_datetime') - F('login_datetime'), output_field=DurationField() ) ) # 2. 按用户分组,统计累计登录时长和平均登录时长 user_stats = login_logout_pairs.values('user', 'user__username').annotate( total_duration=Sum('session_duration'), avg_duration=Avg('session_duration') ) # 3. 格式化返回结果 result = [] for stat in user_stats: result.append({ "用户ID": stat['user'], "用户名": stat['user__username'], "累计登录时长": str(stat['total_duration']), "平均登录时长": str(stat['avg_duration']) }) return Response(result, status=status.HTTP_200_OK)
注意事项
- 如果业务允许用户同一天多次登录登出,修改模型加关联外键后,只需要把上述的登出记录匹配逻辑替换为外键关联即可,避免多对多匹配错误
- DurationField返回的结果是Python的timedelta类型,转字符串后默认格式为
X天 X:X:X,你可以按需换算为秒、分钟等数值单位返回 - 可以根据需求加时间范围过滤,比如只统计近一个月的记录,在
AllLogin的查询后加filter(login_date__gte=xxx)即可
内容的提问来源于stack exchange,提问作者prashanth
相关产品推荐
相关产品推荐

