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

Django表单is_valid()始终返回True,FileField验证失效求助

文件上传表单验证失效问题

提交表单后,无论上传文件是否符合要求,form.is_valid()始终返回True,页面直接跳转到首页并显示成功提示,无法理解UpdateChecklistForm中的clean()方法为何不生效。

相关代码

forms.py

class UpdateChecklistForm(forms.ModelForm):

    class Meta:
        model = CheckList
        exclude = ['author']

    isps_upload = forms.FileField(
        label='ISPS report',
        widget=forms.FileInput(attrs={'accept': 'pdf'}),
        required=False
    )
    crewlist_upload = forms.FileField(
        label='Crew List',
        widget=forms.FileInput(attrs={'accept': 'pdf'}),
        required=False
    )

    def clean(self):
        self.check_isps()
        self.check_crewlist()
        return self.cleaned_data

    def check_isps(self):
        try:
            content = self.cleaned_data["isps_upload"]
            content_type = content.content_type.split('/')[0]
            if content.size > int(MAX_UPLOAD_SIZE):
                self.add_error(
                    'isps_upload',
                    _(f"Please keep file size under {(filesizeformat(MAX_UPLOAD_SIZE))}. "
                      f"Current file size {filesizeformat(content.size)}")
                )
            extension = os.path.splitext(content.name)[1]  
            VALID_EXTENSIONS = ['.pdf', '.doc', '.docx']
            if not extension.lower() in VALID_EXTENSIONS:
                self.add_error(
                    'isps_upload',
                    _('Only files with "pdf" or "doc/docx" extensions are supported, '
                      'received: "%s" file.' % extension)
                )
            return content
        except AttributeError:
            pass

    def check_crewlist(self):
        try:
            content = self.cleaned_data["crewlist_upload"]
            content_type = content.content_type.split('/')[0]
            if content.size > int(MAX_UPLOAD_SIZE):
                self.add_error(
                    'crewlist_upload',
                    _(f"Please keep file size under {(filesizeformat(MAX_UPLOAD_SIZE))}. "
                      f"Current file size {filesizeformat(content.size)}")
                )
            extension = os.path.splitext(content.name)[1]  # [0] returns path+filename
            VALID_EXTENSIONS = ['.pdf', '.doc', '.docx']
            if not extension.lower() in VALID_EXTENSIONS:
                self.add_error(
                    'crewlist_upload',
                    _('Only files with "pdf" or "doc/docx" extensions are supported, '
                      'received: "%s" file.' % extension)
                )
            return content
        except AttributeError:
            pass

views.py

@login_required
def update_checklist(request, pk):
    instance = get_object_or_404(CheckList, id=pk)
    form = UpdateChecklistForm(request.POST or None, instance=instance)
    if request.method == 'POST':
        if form.is_valid():
            instance = form.save(commit=False)
            instance.author = request.user
            ETA = request.POST['ETA']
            try:
                dispatcher = request.POST['dispatcher']
                if dispatcher:
                    dispatcher = 'Done'
            except Exception as e:
                dispatcher = '-//-'
            instance.author = request.user
            try:
                user = request.user
                if hasattr(user, '_wrapped') and hasattr(user, '_setup'):
                    if user._wrapped.__class__ == object:
                        user._setup()
                    user = user._wrapped
                if user:
                    user = user.last_name + " " + user.first_name
            except Exception as e:
                user = '-//-'
            instance.save()
            sendTelegram(...some stuff...)
            messages.success(request, 'Success')
            return redirect('home')
        else:
            return HttpResponse('error')
    context = {
        'form': form
    }
    return render(request, 'someurl/update.html', context)

问题原因及解决方案

1. 核心问题:未传递request.FILES到表单

Django处理文件上传时,必须将request.FILES传入表单构造函数,否则表单无法获取上传的文件,cleaned_data中对应的文件字段为None,导致check_isps和check_crewlist里的验证逻辑因捕获AttributeError直接跳过,不会添加错误信息,form.is_valid()自然返回True。

修改视图中表单初始化代码:

form = UpdateChecklistForm(request.POST or None, request.FILES or None, instance=instance)

2. 优化表单验证逻辑

  • 替换宽泛的AttributeError捕获,改为明确判断字段是否存在,避免忽略其他潜在错误:

    def check_isps(self):
        content = self.cleaned_data.get("isps_upload")
        if not content:
            return
        if content.size > int(MAX_UPLOAD_SIZE):
            self.add_error(
                'isps_upload',
                _(f"Please keep file size under {(filesizeformat(MAX_UPLOAD_SIZE))}. "
                  f"Current file size {filesizeformat(content.size)}")
            )
        extension = os.path.splitext(content.name)[1].lower()
        VALID_EXTENSIONS = ['.pdf', '.doc', '.docx']
        if extension not in VALID_EXTENSIONS:
            self.add_error(
                'isps_upload',
                _('Only files with "pdf" or "doc/docx" extensions are supported, '
                  'received: "%s" file.' % extension)
            )
    

    check_crewlist方法做同样修改。

  • 删除未使用的content_type变量,简化代码。

3. 视图中通过表单获取数据

视图中直接从request.POST读取数据的做法不规范,应该通过表单的cleaned_data获取,确保数据经过表单验证:

if form.is_valid():
    instance = form.save(commit=False)
    instance.author = request.user
    ETA = form.cleaned_data['ETA']
    dispatcher = form.cleaned_data.get('dispatcher', '-//-')
    if dispatcher:
        dispatcher = 'Done'
    # 后续逻辑保留

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 22:57:22