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

Django模型clean函数抛出ValidationError后FileField文件丢失求助

解决Django Admin验证失败后保留已上传文件的问题

Django Admin默认在表单验证失败时不会保留已上传的文件——临时上传的文件会在请求结束后被清理,而普通字段的POST数据会自动回显。要实现验证失败时保留已上传文件,可以通过自定义ModelForm和ModelAdmin,结合临时存储与session的方式实现。

实现步骤

1. 自定义ModelForm

在表单初始化时从session读取之前保存的临时文件路径,回显到FileField:

from django import forms
from .models import License

class LicenseForm(forms.ModelForm):
    class Meta:
        model = License
        fields = "__all__"

    def __init__(self, *args, **kwargs):
        self.request = kwargs.pop("request", None)
        super().__init__(*args, **kwargs)
        
        # 若为POST请求且session中存在临时文件,设置初始值
        if self.request and self.request.method == "POST":
            file_field_name = "your_file_field"  # 替换为你的FileField字段名
            temp_file_path = self.request.session.get(file_field_name)
            if temp_file_path:
                from django.core.files.storage import default_storage
                if default_storage.exists(temp_file_path):
                    self.fields[file_field_name].initial = temp_file_path

2. 自定义ModelAdmin

重写changeform_view方法,在验证失败前保存上传的临时文件到存储和session,验证成功后清理临时文件:

from django.contrib import admin
from django.core.files.storage import default_storage
from .models import License
from .forms import LicenseForm

class LicenseAdmin(admin.ModelAdmin):
    form = LicenseForm

    def get_form(self, request, obj=None, **kwargs):
        # 把request传递给表单
        kwargs["request"] = request
        return super().get_form(request, obj, **kwargs)

    def changeform_view(self, request, object_id=None, form_url="", extra_context=None):
        file_field_name = "your_file_field"  # 替换为你的FileField字段名
        
        if request.method == "POST":
            # 保存上传的文件到临时存储
            if file_field_name in request.FILES:
                uploaded_file = request.FILES[file_field_name]
                temp_path = default_storage.save(f"temp_uploads/{uploaded_file.name}", uploaded_file)
                request.session[file_field_name] = temp_path
            
            # 验证表单
            form = self.get_form(request)(
                request.POST, request.FILES, instance=self.get_object(request, object_id)
            )
            if form.is_valid():
                # 验证成功,清除session中的临时文件路径并删除文件
                if file_field_name in request.session:
                    temp_path = request.session.pop(file_field_name)
                    if default_storage.exists(temp_path):
                        default_storage.delete(temp_path)
        
        return super().changeform_view(request, object_id, form_url, extra_context)

注意事项

  • 替换代码中your_file_field为你实际的FileField字段名称
  • 临时存储目录temp_uploads需要提前创建,或确保Django使用的存储后端支持自动创建目录
  • 需定期清理临时文件,可通过定时任务(如Celery、Django Q)删除temp_uploads目录下的过期文件
  • 多文件上传场景需调整代码以支持多个FileField

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 20:22:20