Python Django-上载的文件类型验证

Python Django-上载的文件类型验证,python,validation,file-upload,django-forms,file-type,Python,Validation,File Upload,Django Forms,File Type,我需要验证上传文件的文件类型,应该只允许pdf,普通测试和MS word文件。这是我的模型和带有验证功能的表单。但是,即使没有扩展名,我也可以上传文件 class Section(models.Model): content = models.FileField(upload_to="documents") class SectionForm(forms.ModelForm): class Meta: model = Section FILE_EXT_W

我需要验证上传文件的文件类型,应该只允许pdf,普通测试和MS word文件。这是我的模型和带有验证功能的表单。但是,即使没有扩展名,我也可以上传文件

class Section(models.Model):
    content = models.FileField(upload_to="documents")

class SectionForm(forms.ModelForm):
    class Meta:
        model = Section
    FILE_EXT_WHITELIST = ['pdf','text','msword']

    def clean_content(self):
        content = self.cleaned_data['content']
        if content:
            file_type = content.content_type.split('/')[0]
            print file_type
            if len(content.name.split('.')) == 1:
                raise forms.ValidationError("File type is not supported.")
            if content.name.split('.')[-1] in self.FILE_EXT_WHITELIST:
                return content
            else:
                raise forms.ValidationError("Only '.txt' and '.pdf' files are allowed.")
这里是景色

def section_update(request, object_id):
    section = models.Section.objects.get(pk=object_id)
    if 'content' in request.FILES:
            if request.FILES['content'].name.split('.')[-1] == "pdf":
                content_file = ContentFile(request.FILES['content'].read())
                content_type = "pdf"
                section.content.save("test"+'.'+content_type , content_file)
                section.save()

在我看来,我只是从
request.file
保存文件。我认为save()会调用clean_内容并进行内容类型验证。我想,clean_内容根本不需要验证。

你的方法行不通:作为攻击者,我可以简单地伪造HTML头,向你发送任何mime类型
text/plain
的内容

正确的解决方案是在Unix上使用类似于
file(1)
的工具来检查文件的内容,以确定它是什么。请注意,没有好的方法可以知道某些内容是否真的是纯文本。如果文件以16位Unicode格式保存,“纯文本”甚至可以包含0字节


有关如何执行此操作的选项,请参见此问题:

您可以使用python magic

import magic
magic.from_file('/my/file.jpg', mime=True)
# image/jpeg

这是一个老问题,但对于以后的用户来说,注释中提到的主要问题是为什么不进行字段验证,以及django文档中描述的调用is_valid()时执行字段验证。因此,必须使用以下内容来激活现场验证:

section = models.Section.objects.get(pk=object_id)    
if request.method == 'POST':    
   form = SectionForm(request.POST, request.FILES)
   if form.is_valid:
      do_something_with_form
表单验证发生在数据被清除时。如果要自定义此过程,可以在不同的位置进行更改,每个位置都有不同的用途。表单处理期间运行三种类型的清理方法。这些通常在调用表单上的is_valid()方法时执行


是的,我同意你的看法。django文档本身坚持“信任但验证”。但是我需要为一个无效文件提出
表单.ValidationError
,不管它是如何被验证的。不,
def clean_content
根本不调用。我想,我们不能混淆模型和它的形式来引起验证错误。我将按照您的建议检查该文件,如果验证失败,我将重定向到错误视图。谢谢,啊。在这种情况下,您的问题应该是“为什么从未调用clean_content()”,我建议您提出一个新问题。