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

Django项目用户站点时长统计:能否用默认登录表单加回调?

解决Django用户停留时长统计的方案

django.contrib.auth.urls里的默认登录/登出视图本身没有直接暴露回调函数参数,但可以通过以下几种方式实现你的需求,无需完全重写视图和表单:

1. 使用Django认证信号(最简便方案)

Django内置了认证相关的信号,能在用户登录、登出时自动触发自定义逻辑,完全保留默认登录表单和视图:

  • user_logged_in:用户成功登录时触发
  • user_logged_out:用户登出时触发

实现步骤:

  • 在你的app下创建signals.py文件,编写信号处理函数:
from django.contrib.auth.signals import user_logged_in, user_logged_out
from django.dispatch import receiver
from django.utils import timezone
from .models import UserSession  # 替换为你存储登录记录的模型

@receiver(user_logged_in)
def record_login_info(sender, request, user, **kwargs):
    # 记录登录时间、用户及IP
    UserSession.objects.create(
        user=user,
        login_time=timezone.now(),
        ip_address=request.META.get('REMOTE_ADDR')
    )

@receiver(user_logged_out)
def record_logout_info(sender, request, user, **kwargs):
    # 更新对应登录记录的登出时间,计算停留时长
    if user.is_authenticated:
        latest_session = UserSession.objects.filter(user=user, logout_time__isnull=True).last()
        if latest_session:
            latest_session.logout_time = timezone.now()
            latest_session.duration = latest_session.logout_time - latest_session.login_time
            latest_session.save()
  • 在app的apps.py中注册信号,确保Django启动时加载:
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  # 对应上面的signals文件路径
  • 在settings.py中把你的app配置改为上述类,而非直接写app名称:
INSTALLED_APPS = [
    # ...其他app
    'your_app_name.apps.YourAppConfig',
]

2. 继承默认认证视图扩展(更灵活)

如果需要在登录/登出前后做额外操作(比如自定义跳转逻辑),可以继承默认的LoginView和LogoutView,重写对应方法,同时保留默认表单:

示例代码:

from django.contrib.auth.views import LoginView, LogoutView
from django.utils import timezone
from .models import UserSession

class CustomLoginView(LoginView):
    # 保留默认登录模板
    template_name = 'registration/login.html'

    def form_valid(self, form):
        # 先执行父类的登录逻辑
        response = super().form_valid(form)
        # 自定义登录记录逻辑
        UserSession.objects.create(
            user=self.request.user,
            login_time=timezone.now(),
            ip_address=self.request.META.get('REMOTE_ADDR')
        )
        return response

class CustomLogoutView(LogoutView):
    def dispatch(self, request, *args, **kwargs):
        # 先处理登出记录
        if request.user.is_authenticated:
            latest_session = UserSession.objects.filter(user=request.user, logout_time__isnull=True).last()
            if latest_session:
                latest_session.logout_time = timezone.now()
                latest_session.duration = latest_session.logout_time - latest_session.login_time
                latest_session.save()
        # 再执行父类的登出逻辑
        return super().dispatch(request, *args, **kwargs)
  • 在urls.py中替换默认auth路由:
from django.urls import path
from .views import CustomLoginView, CustomLogoutView

urlpatterns = [
    path('login/', CustomLoginView.as_view(), name='login'),
    path('logout/', CustomLogoutView.as_view(), name='logout'),
    # 其他auth路由(如密码重置)可继续使用django.contrib.auth.urls的默认配置
]

3. 补充:处理用户未主动登出的情况

用户可能直接关闭浏览器而不触发登出操作,可通过以下方式处理:

  • 在settings.py设置会话过期时间:SESSION_COOKIE_AGE = 3600(单位:秒,示例为1小时)
  • 借助定时任务(如Celery)定期清理过期未登出的会话,将停留时长计算为会话过期时间减去登录时间

内容的提问来源于stack exchange,提问作者niaei

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 06:15:44