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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 00:54:08