Django使用ModelForm上传CSS文件时获取失败、校验不生效如何解决
问题根本原因
- 前端表单未配置
enctype="multipart/form-data"属性:浏览器提交带文件的表单时必须指定该编码类型,否则只会将文件名作为普通字符串传到request.POST,不会将文件内容写入request.FILES,这就是你看到request.FILES为空、request.POST['file']只有文件名的核心原因。 - 自定义字段的异常捕获逻辑不合理:当没有拿到文件对象触发
AttributeError时你直接pass跳过了校验,所以就算没有上传有效文件,表单也会判定为合法。 - 视图函数的POST处理分支缺少返回值,Django要求所有请求分支都必须返回HttpResponse对象,否则会触发运行错误。
修复步骤
1. 修改前端模板表单
给<form>标签加上编码类型属性:
<form method="POST" enctype="multipart/form-data"> {% csrf_token %} <div class="form-title">Upload a new CSS file</div> {{ form.as_p }} <div class="button-area"> <button id="go" type="submit">Go</button> </div> </form>
2. 优化自定义FileField逻辑
- 修改
max_upload_size的默认值为数值类型,避免后续比较报错 - 调整异常捕获逻辑,文件为空时主动抛出校验错误
class FileField(models.FileField): def __init__(self, *args, **kwargs): self.content_types = kwargs.pop('content_types', []) # 修改默认值为数值类型,默认最大5MB self.max_upload_size = kwargs.pop('max_upload_size', mb(5)) super().__init__(*args, **kwargs) def clean(self, *args, **kwargs): data = super().clean(*args, **kwargs) # 先判断是否拿到了文件 if not data: raise forms.ValidationError('请选择要上传的文件') file = data.file try: content_type = file.content_type if content_type in self.content_types: if file.size > self.max_upload_size: raise forms.ValidationError('请保持文件大小在 {} 以内,当前文件大小为 {}' .format(filesizeformat(self.max_upload_size), filesizeformat(file.size))) else: raise forms.ValidationError('不支持的文件格式,请上传CSS文件') except AttributeError: raise forms.ValidationError('文件读取失败,请重新上传') return data
3. 修复视图函数返回逻辑
给POST请求分支添加返回值,校验成功后可以保存文件或者返回成功提示,校验失败返回带错误信息的表单:
def cssUploadView(request): if request.method == 'POST': form = forms.CssCreateForm(request.POST, request.FILES) if form.is_valid(): # 校验成功可以执行保存操作 form.save() print('---------') print(form.cleaned_data['file']) # 可根据需求跳转到成功页或者返回成功提示 return HttpResponse('上传成功') else: print('not valid') else: form = forms.CssCreateForm() # 把POST校验失败的分支和GET分支的返回统一放到最后 return render(request, 'css/css_create.html', { 'form': form, })
额外优化建议
仅校验content-type很容易被伪造,你可以额外增加文件内容校验,比如读取文件前若干字符判断是否为合法CSS格式,避免用户修改后缀绕过校验。
内容的提问来源于stack exchange,提问作者Weilory
相关产品推荐
相关产品推荐

