Django中使用Signal实现用户每日仅一条登录日志记录的技术问询
解决用户每日仅生成一条登录日志的问题
我来帮你梳理下问题所在,然后给出可行的解决方案:
首先看你现有代码里的几个关键问题:
- 模型关联错误:
UserLogs用了OneToOneField,这意味着一个用户只能对应一条日志记录,完全不符合「每天一条」的需求,必须改成ForeignKey才能支持多日期的日志存储。 - 存在性判断逻辑错误:你创建
UserLogs实例后检查insert.id.exists()是无效的——新实例还没保存,id是None,而且exists()是QuerySet的方法,不是实例方法,这个判断根本起不到作用。
修正后的完整代码
第一步:修改UserLogs模型
from django.db import models from django.contrib.auth.models import User from django.utils import timezone class UserLogs(models.Model): user = models.ForeignKey(User, related_name="login_logs", on_delete=models.CASCADE) time_in = models.DateTimeField(default=timezone.now) time_out = models.DateTimeField(null=True, blank=True) class Meta: # 添加数据库级约束,确保同一个用户每天只能有一条登录日志 constraints = [ models.UniqueConstraint( models.Func(models.F('time_in'), function='DATE'), 'user', name='unique_user_daily_login' ) ]
第二步:修正登录信号处理函数
from django.contrib.auth.signals import user_logged_in from django.dispatch import receiver from django.utils import timezone from datetime import date, datetime @receiver(user_logged_in) def post_login(sender, request, user, **kwargs): # 定义当天的时间范围:从00:00到23:59:59 today = date.today() start_of_day = datetime.combine(today, datetime.min.time()) end_of_day = datetime.combine(today, datetime.max.time()) # 检查用户当天是否已有登录日志 has_today_log = UserLogs.objects.filter( user=user, time_in__range=(start_of_day, end_of_day) ).exists() if not has_today_log: # 当天无日志,创建新记录 UserLogs.objects.create(user=user, time_in=timezone.now()) print(f"已为用户 {user.username} 创建今日登录日志") else: print(f"用户 {user.username} 今日已有登录日志,无需重复创建")
额外优化(可选)
如果需要记录用户的登出时间,可以添加登出信号处理:
from django.contrib.auth.signals import user_logged_out @receiver(user_logged_out) def post_logout(sender, request, user, **kwargs): today = date.today() start_of_day = datetime.combine(today, datetime.min.time()) end_of_day = datetime.combine(today, datetime.max.time()) # 找到用户今日的登录日志,更新登出时间 try: log = UserLogs.objects.get( user=user, time_in__range=(start_of_day, end_of_day) ) log.time_out = timezone.now() log.save() print(f"已更新用户 {user.username} 今日登出时间") except UserLogs.DoesNotExist: print(f"未找到用户 {user.username} 今日登录日志,跳过登出记录")
内容的提问来源于stack exchange,提问作者Yuno
相关产品推荐
相关产品推荐

