如何使用FileField限制ModelForms文件上传的文件类型?

时间:2011-06-23 21:30:57

标签: django django-forms django-file-upload

我的目标是将Django ModelForm上的FileField限制为PDF和Word文档。我用google搜索的答案都涉及创建一个单独的文件处理程序,但我不知道如何在ModelForm的上下文中这样做。 settings.py中是否有可用于限制上传文件类型的设置?

8 个答案:

答案 0 :(得分:43)

创建一个验证方法,如:

def validate_file_extension(value):
    if not value.name.endswith('.pdf'):
        raise ValidationError(u'Error message')

并将其包含在FileField验证程序中,如下所示:

actual_file = models.FileField(upload_to='uploaded_files', validators=[validate_file_extension])

此外,您不应手动设置模型允许的扩展名,而应在settings.py上创建一个列表并对其进行迭代。

修改

要过滤多个文件:

def validate_file_extension(value):
  import os
  ext = os.path.splitext(value.name)[1]
  valid_extensions = ['.pdf','.doc','.docx']
  if not ext in valid_extensions:
    raise ValidationError(u'File not supported!')

答案 1 :(得分:18)

使用文件名的扩展名进行验证不是一致的方法。例如,我可以将picture.jpg重命名为picture.pdf,验证不会引发错误。

更好的方法是检查文件的content_type。

验证方法

def validate_file_extension(value):
    if value.file.content_type != 'application/pdf':
        raise ValidationError(u'Error message')

<强>用法

actual_file = models.FileField(upload_to='uploaded_files', validators=[validate_file_extension])

答案 2 :(得分:4)

为了更通用的用法,我写了一个小类replicate.fetch.max.bytes,它扩展了Django的内置ExtensionValidator。它接受单个或多个扩展,以及可选的自定义错误消息。

RegexValidator

现在您可以定义与字段内联的验证器,例如:

class ExtensionValidator(RegexValidator):
    def __init__(self, extensions, message=None):
        if not hasattr(extensions, '__iter__'):
            extensions = [extensions]
        regex = '\.(%s)$' % '|'.join(extensions)
        if message is None:
            message = 'File type not supported. Accepted types are: %s.' % ', '.join(extensions)
        super(ExtensionValidator, self).__init__(regex, message)

    def __call__(self, value):
        super(ExtensionValidator, self).__call__(value.name)

答案 3 :(得分:4)

更简单的方法如下表格

file = forms.FileField(widget=forms.FileInput(attrs={'accept':'application/pdf'}))

答案 4 :(得分:3)

我沿着这些方向使用了某些东西(注意,&#34; pip install filemagic&#34;这是必需的......):

import magic
def validate_mime_type(value):
    supported_types=['application/pdf',]
    with magic.Magic(flags=magic.MAGIC_MIME_TYPE) as m:
        mime_type=m.id_buffer(value.file.read(1024))
        value.file.seek(0)
    if mime_type not in supported_types:
        raise ValidationError(u'Unsupported file type.')

你也可以将前面的例子加入到这里 - 例如也检查扩展/上传类型(作为主要检查可能比魔术更快。)这仍然不是万无一失 - 但它&#39;更好,因为它更依赖于文件中的数据,而不是浏览器提供的标题。

注意:这是一个验证程序功能,您希望将其添加到FileField模型的验证程序列表中。

答案 5 :(得分:1)

我发现检查文件类型的最佳方法是检查其内容类型。我还要补充一点,进行类型检查的最佳场所之一是表单验证。我会有一个表单和一个验证如下:

class UploadFileForm(forms.Form):
    file = forms.FileField()

    def clean_file(self):
        data = self.cleaned_data['file']

        # check if the content type is what we expect
        content_type = data.content_type
        if content_type == 'application/pdf':
            return data
        else:
            raise ValidationError(_('Invalid content type'))

以下文档链接可能会有所帮助: https://docs.djangoproject.com/en/3.1/ref/files/uploads/https://docs.djangoproject.com/en/3.1/ref/forms/validation/

答案 6 :(得分:0)

我通过在ModelForm上使用clean_ [your_field]方法来处理这个问题。您可以在settings.py中设置可接受的文件扩展名列表,以便在您的干净方法中进行检查,但没有内置的settings.py来限制上传类型。

例如,Django-Filebrowser采用在settings.py中创建可接受文件扩展名列表的方法。

希望能帮到你。

答案 7 :(得分:0)

从1.11开始,Django为此使用了FileExtensionValidator

class SomeDocument(Model):
    document = models.FileFiled(validators=[
        FileExtensionValidator(allowed_extensions=['pdf', 'doc'])])

如@savp所述,您还需要自定义窗口小部件,以便用户一开始就无法选择不适当的文件:

class SomeDocumentForm(ModelForm):
    class Meta:
        model = SomeDocument
        widgets = {'document': FileInput(attrs={'accept': 'application/pdf,application/msword'})}
        fields = '__all__'

您可能需要弄弄accept才能准确地确定达到目的所需的MIME类型。

正如其他人所提到的那样,这一切都不会阻止某人将badstuff.exe重命名为innocent.pdf并通过您的表单上传它-您仍然需要安全地处理上传的文件。拥有python-magic库之类的内容后,它们便可以帮助您确定实际的文件类型。