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

Django:如何检测会话超时?解决超时未清理登录用户表问题

解决Django会话超时自动清理在线用户表的问题

这个问题我之前也碰到过——手动登出能正常删记录,但会话超时就不行,因为Django的会话过期清理是后台静默执行的,不会触发我们写的登出视图或者user_logged_out信号。不过有几种靠谱的方案能解决这个问题,给你梳理一下:

方法一:利用Session模型的post_delete信号(最推荐)

核心思路是:当Django的clearsessions命令删除过期会话时,会触发Session模型的post_delete信号,我们在这个信号里同步删除对应的在线用户记录。

步骤1:给在线用户表添加session_key字段

首先建议给你的在线用户表(比如叫OnlineUser)加一个session_key字段,用来关联Django的会话表(django_session),这样能精准定位到每个会话对应的用户,避免误删同一用户其他设备的登录记录:

# models.py
from django.db import models

class OnlineUser(models.Model):
    username = models.CharField(max_length=150, unique=True)
    session_key = models.CharField(max_length=40, unique=True)  # 关联会话的session_key

    def __str__(self):
        return self.username

步骤2:登录时关联会话

在用户登录时,不仅要把用户名存入OnlineUser,还要把当前会话的session_key也存进去。可以用user_logged_in信号来实现:

# signals.py
from django.contrib.auth.signals import user_logged_in
from django.dispatch import receiver
from .models import OnlineUser

@receiver(user_logged_in)
def add_online_user_on_login(sender, request, user, **kwargs):
    # 先删除该用户可能存在的旧记录(比如同一用户之前的登录会话)
    OnlineUser.objects.filter(username=user.username).delete()
    # 创建新的在线用户记录,关联当前会话
    OnlineUser.objects.create(
        username=user.username,
        session_key=request.session.session_key
    )

步骤3:监听Session删除信号

当过期会话被clearsessions命令删除时,触发post_delete信号,同步删除对应的在线用户记录:

# signals.py 继续添加
from django.db.models.signals import post_delete
from django.contrib.sessions.models import Session

@receiver(post_delete, sender=Session)
def remove_online_user_on_session_delete(sender, instance, **kwargs):
    # 根据被删除的会话key,清理在线用户表
    OnlineUser.objects.filter(session_key=instance.session_key).delete()

步骤4:注册信号

别忘了在app的apps.py里注册信号,确保项目启动时信号能被加载:

# apps.py
from django.apps import AppConfig

class YourAppConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'your_app_name'

    def ready(self):
        import your_app_name.signals  # 导入信号模块

步骤5:确保clearsessions定时运行

Django默认不会自动运行clearsessions,你需要设置定时任务:

  • 如果用Linux,可以加个cron任务,每天执行一次:0 0 * * * /path/to/your/python /path/to/your/manage.py clearsessions
  • 如果用Django的第三方定时任务库(比如django-crontab),可以在settings里配置:
CRONJOBS = [
    ('0 0 * * *', 'django.core.management.call_command', ['clearsessions']),
]

方法二:自定义会话后端

如果需要更精细化的会话过期控制,可以自定义SessionStore,重写过期逻辑:

# backends.py
from django.contrib.sessions.backends.db import SessionStore
from .models import OnlineUser

class CustomSessionStore(SessionStore):
    def expire(self):
        # 先执行父类的过期逻辑
        super().expire()
        # 清理对应的在线用户记录
        OnlineUser.objects.filter(session_key=self.session_key).delete()

然后在settings.py里指定自定义的会话引擎:

SESSION_ENGINE = 'your_app_name.backends.CustomSessionStore'

这个方法适合需要在会话过期时做额外操作的场景,但相对复杂一点。

方法三:定时任务直接清理过期用户

如果上面的信号方案不适用,也可以写一个定时任务,定期扫描过期会话并清理对应的在线用户:

步骤1:编写自定义管理命令

# your_app/management/commands/clean_expired_online_users.py
from django.core.management.base import BaseCommand
from django.contrib.sessions.models import Session
from django.utils import timezone
from .models import OnlineUser

class Command(BaseCommand):
    help = '清理会话已过期的在线用户记录'

    def handle(self, *args, **options):
        # 获取所有过期的会话
        expired_sessions = Session.objects.filter(expire_date__lt=timezone.now())
        # 提取这些会话的key列表
        expired_session_keys = expired_sessions.values_list('session_key', flat=True)
        # 删除对应的在线用户记录
        deleted_count, _ = OnlineUser.objects.filter(session_key__in=expired_session_keys).delete()
        
        self.stdout.write(self.style.SUCCESS(f"成功清理{deleted_count}条过期在线用户记录"))

步骤2:设置定时任务

和clearsessions一样,把这个命令加入定时任务,比如每天执行一次,就能自动清理过期的在线用户记录了。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 07:44:31