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命令,删除过期会话的同时清理目录:
- 在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}")
- 用定时任务(如Linux Cron)定期执行:
0 0 * * * /path/to/venv/bin/python /path/to/project/manage.py custom_clearsessions
方式2:使用会话删除信号
通过Django信号监听会话删除事件,自动触发目录清理:
- 在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}")
- 在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
相关产品推荐
相关产品推荐

