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

如何让Django登录日志Middleware仅在用户登录时执行而非每次API调用?

问题:Django登录日志中间件仅在用户登录时执行一次的修改方案

我创建了一个用于记录用户登录活动日志的Django Middleware,但它会在每次API调用时执行,其中使用ActivityLog模型记录日志条目。

原Middleware代码:

class UserActivityMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        # Set a flag in the session to indicate that the user has been logged in during this session
        request.session['user_logged_in'] = request.session.get('user_logged_in', False)

        response = self.get_response(request)

        # Check if the user is authenticated, has just logged in, and hasn't been logged during this session
        if (
            request.user.is_authenticated
            and request.user.last_login is not None
            and request.session.get('user_logged_in', False) is False
            and not request.path.startswith('/static/')
            and not request.path.startswith('/media/')
        ):
            print("reached middleware")
            print(f"User: {request.user.username}")
            print(f"Last Login: {request.user.last_login}")
            print(f"Session Flag: {request.session.get('user_logged_in')}")
            print(f"Request Path: {request.path}")

            # Log the user login activity
            ActivityLog.objects.create(
                user=request.user,
                action="Login",
                target_model="User",
                target_object_id=request.user.id,
                details=f"User {request.user.username} logged in at {timezone.now()}."
            )

            # Set a flag in the session to indicate that the user has been logged in during this session
            request.session['user_logged_in'] = True

        return response

请问我该如何修改,才能让它仅在用户登录时执行一次?


修改方案

方法一:监听Django登录信号(推荐)

直接用Django内置的user_logged_in信号,这是最精准的方式——只有用户成功完成登录动作时才会触发,完全避免中间件遍历所有请求的问题:

# 在你的app目录下新建signals.py文件
from django.contrib.auth.signals import user_logged_in
from django.dispatch import receiver
from django.utils import timezone
from .models import ActivityLog

@receiver(user_logged_in)
def log_user_login(sender, request, user, **kwargs):
    ActivityLog.objects.create(
        user=user,
        action="Login",
        target_model="User",
        target_object_id=user.id,
        details=f"User {user.username} logged in at {timezone.now()}."
    )

然后在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  # 对应上面的signals.py路径

方法二:优化中间件判断逻辑

如果坚持使用中间件,需要精准锁定「登录请求」场景,避免所有请求都进入判断流程:

class UserActivityMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        # 记录请求前的用户认证状态
        was_authenticated_before = request.user.is_authenticated
        # 获取会话中已有的登录标记
        session_logged_in = request.session.get('user_logged_in', False)

        response = self.get_response(request)

        # 仅当以下条件全部满足时,才记录登录日志:
        # 1. 请求前未认证,请求后已认证(说明刚完成登录)
        # 2. 当前会话还未记录过登录日志
        # 3. 请求路径是登录接口(替换成你的实际登录路径,比如'/api/auth/login/')
        if (
            not was_authenticated_before
            and request.user.is_authenticated
            and not session_logged_in
            and request.path == '/accounts/login/'
            and not request.path.startswith('/static/')
            and not request.path.startswith('/media/')
        ):
            ActivityLog.objects.create(
                user=request.user,
                action="Login",
                target_model="User",
                target_object_id=request.user.id,
                details=f"User {request.user.username} logged in at {timezone.now()}."
            )
            request.session['user_logged_in'] = True

        return response

原代码问题说明

原代码的核心问题是没有精准锁定「用户刚刚完成登录」的动作:虽然会话标记能避免重复创建日志,但中间件会在每一次请求时都执行判断逻辑。而且原代码在请求开始时就重置user_logged_in标记的操作冗余,反而可能导致逻辑混乱。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 08:15:01