如何在Django视图函数create_page中执行分发的信号?
技术指导:表单前置文件上传与Tus信号处理
现有代码的核心问题
- 在视图函数内部定义
@receiver会导致重复注册信号接收器:每次请求create_page视图都会新增一个接收器,后续上传的文件会触发所有已注册的接收器,造成数据混乱。 - 无法保证
files列表与当前请求的绑定:多用户并发请求时,不同用户的上传文件会混入同一个列表,导致文件关联错误。 attach.file = f直接赋值文件名不符合Django FileField要求:需要处理文件路径或使用File对象完成关联。
修正方案步骤
1. 移除视图内信号接收器,改用独立接收器+会话关联
把信号接收器移到signals.py中,通过**用户会话(session)**绑定当前请求的上传文件,避免跨请求污染:
修改signals.py
from django.dispatch import receiver from django.contrib.sessions.models import Session from .models import Attach from django.conf import settings @receiver(tus_upload_finished_signal) def handle_tus_upload(sender, **kwargs): # 从metadata中获取前端传入的session_key session_key = kwargs['metadata'].get('session_key') if not session_key: return # 从会话中读取已上传文件列表,追加新文件信息 session = Session.objects.get(session_key=session_key) upload_files = session.get('tus_upload_files', []) upload_files.append({ 'filename': kwargs['filename'], 'file_path': kwargs['upload_file_path'], 'file_size': kwargs['file_size'] }) session['tus_upload_files'] = upload_files session.save()
2. 前端上传时传递session_key
前端发起Tus上传请求时,需将当前用户的session_key放入metadata,确保后端能关联到对应请求会话:
// 示例tus-js-client上传代码 const upload = new tus.Upload(file, { endpoint: '/tus/upload/', metadata: { filename: file.name, session_key: '{{ request.session.session_key }}' // Django模板渲染会话key }, // 其他上传配置 });
3. 重构create_page视图,从会话读取文件并关联Post
def create_page(request): if request.method == 'POST': form = PostForm(request.POST) if form.is_valid(): post = form.save(commit=False) post.author = request.user post.save() # 从会话获取当前用户的上传文件 upload_files = request.session.get('tus_upload_files', []) for file_info in upload_files: from django.core.files import File attach = Attach() attach.post = post attach.filename = file_info['filename'] # 为FileField赋值文件对象 with open(file_info['file_path'], 'rb') as f: attach.file.save(file_info['filename'], File(f), save=False) attach.file_size = file_info['file_size'] attach.save() # 清空会话中的上传记录,避免重复关联 if 'tus_upload_files' in request.session: del request.session['tus_upload_files'] return redirect('index_page') else: form = PostForm() return render(request, 'core/_form.html', {'form': form})
4. 确保Attach模型字段适配需求
# models.py示例 from django.db import models from .models import Post class Attach(models.Model): post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='attachments') file = models.FileField(upload_to='attachments/') # 配置文件存储路径 filename = models.CharField(max_length=255, blank=True) file_size = models.IntegerField(blank=True, null=True) uploaded_at = models.DateTimeField(auto_now_add=True)
额外注意事项
- 临时文件清理:Tus上传的临时文件在关联到Attach后,需通过定时任务清理未被关联的冗余文件。
- 权限验证:在
TusUpload的patch方法中,需验证当前用户权限,防止恶意上传。 - 分布式部署适配:多服务器部署时,需将session存储在共享介质(如Redis),避免跨节点会话不一致。
内容的提问来源于stack exchange,提问作者afi
相关产品推荐
相关产品推荐

