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

Django实现会话结束时删除用户专属文件目录

实现会话结束时自动删除上传目录的方案

要解决会话结束(用户关闭标签页/会话过期)时自动删除对应目录的问题,需要结合前端主动通知和后端定时清理两种方式,覆盖正常和异常场景:


一、前端监听页面卸载,主动触发清理请求

当用户正常关闭标签页/浏览器时,通过前端发送可靠请求通知后端删除目录。推荐使用navigator.sendBeacon,它不会阻塞页面卸载,比普通AJAX更稳定。

在页面模板中添加以下JavaScript:

window.addEventListener('unload', function() {
    const sessionKey = "{{ request.session.session_key }}";
    if (sessionKey) {
        const formData = new FormData();
        formData.append('session_key', sessionKey);
        formData.append('csrfmiddlewaretoken', "{{ csrf_token }}");
        
        // 用sendBeacon发送请求,确保页面卸载时请求能完成
        navigator.sendBeacon('/clean-session-dir/', formData);
    }
});

二、后端实现清理逻辑

1. 编写清理目录的视图函数

处理前端发送的清理请求,同时验证会话合法性,防止恶意操作:

from django.http import JsonResponse
from django.views.decorators.csrf import csrf_protect
import shutil
from pathlib import Path
from django.contrib.sessions.models import Session
from django.utils import timezone

# 替换为你的实际PDF存储路径
PDF_PATH = "/your/pdf/storage/path/"

@csrf_protect
def clean_session_dir(request):
    if request.method == 'POST':
        session_key = request.POST.get('session_key')
        if not session_key:
            return JsonResponse({'status': 'error', 'msg': '缺少会话密钥'}, status=400)
        
        try:
            # 验证会话是否存在且未过期
            session = Session.objects.get(session_key=session_key)
            if session.expire_date < timezone.now():
                # 会话已过期,直接删除目录
                dir_path = Path(f"{PDF_PATH}{session_key}")
                if dir_path.exists():
                    shutil.rmtree(dir_path)
                return JsonResponse({'status': 'success'})
            
            # 验证请求会话与目标会话一致,防止跨用户操作
            if request.session.session_key != session_key:
                return JsonResponse({'status': 'error', 'msg': '非法会话密钥'}, status=403)
            
            # 删除目标目录
            dir_path = Path(f"{PDF_PATH}{session_key}")
            if dir_path.exists():
                shutil.rmtree(dir_path)
            return JsonResponse({'status': 'success'})
        
        except Session.DoesNotExist:
            # 会话已被清理,仍尝试删除残留目录
            dir_path = Path(f"{PDF_PATH}{session_key}")
            if dir_path.exists():
                shutil.rmtree(dir_path)
            return JsonResponse({'status': 'success'})
    
    return JsonResponse({'status': 'error', 'msg': '请求方式错误'}, status=405)

2. 配置路由

在项目urls.py中添加清理路由:

from django.urls import path
from .views import clean_session_dir

urlpatterns = [
    # ... 其他路由
    path('clean-session-dir/', clean_session_dir, name='clean_session_dir'),
]

三、处理异常场景:会话过期自动清理

前端通知无法覆盖浏览器崩溃、用户断网等情况,需通过后端定时清理过期会话对应的目录,有两种实现方式:

方式1:自定义会话清理命令

扩展Django自带的clearsessions命令,删除过期会话的同时清理目录:

  1. 在app下创建management/commands目录,新建custom_clearsessions.py:
from django.core.management.commands.clearsessions import Command as ClearSessionsCommand
from django.contrib.sessions.models import Session
from django.utils import timezone
import shutil
from pathlib import Path

PDF_PATH = "/your/pdf/storage/path/"

class Command(ClearSessionsCommand):
    def handle(self, *args, **options):
        # 先执行原生逻辑删除过期会话
        super().handle(*args, **options)
        # 清理对应目录
        expired_sessions = Session.objects.filter(expire_date__lt=timezone.now())
        for session in expired_sessions:
            dir_path = Path(f"{PDF_PATH}{session.session_key}")
            if dir_path.exists():
                try:
                    shutil.rmtree(dir_path)
                except Exception as e:
                    # 捕获删除异常,避免影响其他清理操作
                    print(f"删除目录失败: {e}")
  1. 用定时任务(如Linux Cron)定期执行:
0 0 * * * /path/to/venv/bin/python /path/to/project/manage.py custom_clearsessions

方式2:使用会话删除信号

通过Django信号监听会话删除事件,自动触发目录清理:

  1. 在app下创建signals.py:
from django.contrib.sessions.models import Session
from django.db.models.signals import post_delete
from django.dispatch import receiver
import shutil
from pathlib import Path

PDF_PATH = "/your/pdf/storage/path/"

@receiver(post_delete, sender=Session)
def delete_session_directory(sender, instance, **kwargs):
    dir_path = Path(f"{PDF_PATH}{instance.session_key}")
    if dir_path.exists():
        try:
            shutil.rmtree(dir_path)
        except Exception as e:
            print(f"删除目录失败: {e}")
  1. 在app的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

注意事项

  • 确保服务器进程拥有删除目录和文件的权限;
  • 删除操作添加异常捕获,避免因目录占用等问题导致流程中断;
  • 测试时覆盖正常关闭标签页、会话过期、浏览器崩溃等场景,验证目录清理效果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 10:43:22