关于在Django Admin中实现用户登录登出时间自动记录的可行性问询
解决Django Admin考勤式登录登出记录问题
嘿,你当前的UserLogs模型有个核心问题——用了OneToOneField(User),这就导致每个用户只能有一条登录记录,完全不符合你「每次登录都新增独立记录」的需求。咱们一步步来调整,配合Django的信号机制就能实现你想要的考勤功能。
第一步:重构UserLogs模型
把OneToOneField换成ForeignKey,这样一个用户就能关联多条登录日志了:
from django.db import models from django.contrib.auth.models import User from django.utils.timezone import now class UserLogs(models.Model): user = models.ForeignKey(User, related_name="login_logs", on_delete=models.CASCADE) time_in = models.DateTimeField(default=now) time_out = models.DateTimeField(null=True, blank=True) def __str__(self): return f"{self.user.username} - 登录于 {self.time_in}"
这里把related_name改成login_logs更贴合语义,之后查询用户的所有登录记录也更方便。
第二步:用Django信号自动记录登录/登出
Django内置了用户登录和登出的信号,咱们用它来自动创建和更新日志:
在你的app目录下新建signals.py文件,写入以下代码:
from django.contrib.auth.signals import user_logged_in, user_logged_out from django.dispatch import receiver from django.utils.timezone import now from .models import UserLogs # 用户登录Admin时创建新的登录记录 @receiver(user_logged_in) def create_login_log(sender, request, user, **kwargs): # 只捕获Admin登录的情况(如果不需要区分前台/Admin,可以去掉这个判断) if request.path.startswith('/admin/'): UserLogs.objects.create(user=user) # 用户登出Admin时更新对应记录的登出时间 @receiver(user_logged_out) def update_logout_time(sender, request, user, **kwargs): if request.path.startswith('/admin/'): # 找到该用户最近的、还没记录登出时间的登录记录 latest_unfinished_log = UserLogs.objects.filter( user=user, time_out__isnull=True ).order_by('-time_in').first() if latest_unfinished_log: latest_unfinished_log.time_out = now() latest_unfinished_log.save()
接下来要确保Django启动时能加载这些信号,在app的apps.py里修改:
from django.apps import AppConfig class YourAppConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'your_app_name' # 替换成你的app名称 def ready(self): import your_app_name.signals # 导入信号模块
额外优化建议
- 如果用户直接关闭浏览器没点登出,这条记录的
time_out会一直为空。你可以加个定时任务(比如用Celery),把超过一定时间未登出的记录自动填充超时时间。 - 可以在Admin后台注册
UserLogs模型,方便查看和管理考勤记录:
from django.contrib import admin from .models import UserLogs class UserLogsAdmin(admin.ModelAdmin): list_display = ('user', 'time_in', 'time_out') list_filter = ('user', 'time_in') search_fields = ('user__username',) admin.site.register(UserLogs, UserLogsAdmin)
这样改完之后,每次员工登录Django Admin都会新增一条独立的登录记录,点击登出时会自动更新对应记录的登出时间,完美实现你要的考勤功能~
内容的提问来源于stack exchange,提问作者Yuno
相关产品推荐
相关产品推荐

