只在服务器端的FileField中接受某种文件types

我怎样才能限制FileField只接受某种types的文件(video,audio,PDF等)在一个优雅的方式,服务器端?

一个非常简单的方法是使用自定义validation器。

在你的应用程序的validators.py

 def validate_file_extension(value): import os from django.core.exceptions import ValidationError ext = os.path.splitext(value.name)[1] # [0] returns path+filename valid_extensions = ['.pdf', '.doc', '.docx', '.jpg', '.png', '.xlsx', '.xls'] if not ext.lower() in valid_extensions: raise ValidationError(u'Unsupported file extension.') 

然后在你的models.py

 from .validators import validate_file_extension 

…并使用您的表单域的validation器:

 class Document(models.Model): file = models.FileField(upload_to="documents/%Y/%m/%d", validators=[validate_file_extension]) 

另请参阅: 如何限制使用FileField的ModelForms上传文件types? 。

有一个Django片段可以做到这一点:

 import os from django import forms class ExtFileField(forms.FileField): """ Same as forms.FileField, but you can specify a file extension whitelist. >>> from django.core.files.uploadedfile import SimpleUploadedFile >>> >>> t = ExtFileField(ext_whitelist=(".pdf", ".txt")) >>> >>> t.clean(SimpleUploadedFile('filename.pdf', 'Some File Content')) >>> t.clean(SimpleUploadedFile('filename.txt', 'Some File Content')) >>> >>> t.clean(SimpleUploadedFile('filename.exe', 'Some File Content')) Traceback (most recent call last): ... ValidationError: [u'Not allowed filetype!'] """ def __init__(self, *args, **kwargs): ext_whitelist = kwargs.pop("ext_whitelist") self.ext_whitelist = [i.lower() for i in ext_whitelist] super(ExtFileField, self).__init__(*args, **kwargs) def clean(self, *args, **kwargs): data = super(ExtFileField, self).clean(*args, **kwargs) filename = data.name ext = os.path.splitext(filename)[1] ext = ext.lower() if ext not in self.ext_whitelist: raise forms.ValidationError("Not allowed filetype!") #------------------------------------------------------------------------- if __name__ == "__main__": import doctest, datetime doctest.testmod() 

第一。 在应用程序中创build一个名为formatChecker.py的文件,在该文件中具有您要接受某种文件types的FileField的模型。

这是你的formatChecker.py:

 from django.db.models import FileField from django.forms import forms from django.template.defaultfilters import filesizeformat from django.utils.translation import ugettext_lazy as _ class ContentTypeRestrictedFileField(FileField): """ Same as FileField, but you can specify: * content_types - list containing allowed content_types. Example: ['application/pdf', 'image/jpeg'] * max_upload_size - a number indicating the maximum file size allowed for upload. 2.5MB - 2621440 5MB - 5242880 10MB - 10485760 20MB - 20971520 50MB - 5242880 100MB 104857600 250MB - 214958080 500MB - 429916160 """ def __init__(self, *args, **kwargs): self.content_types = kwargs.pop("content_types") self.max_upload_size = kwargs.pop("max_upload_size") super(ContentTypeRestrictedFileField, self).__init__(*args, **kwargs) def clean(self, *args, **kwargs): data = super(ContentTypeRestrictedFileField, self).clean(*args, **kwargs) 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(_('Please keep filesize under %s. Current filesize %s') % (filesizeformat(self.max_upload_size), filesizeformat(file._size))) else: raise forms.ValidationError(_('Filetype not supported.')) except AttributeError: pass return data 

第二。 在你的models.py中,添加这个:

 from formatChecker import ContentTypeRestrictedFileField 

然后,而不是使用“FileField”,使用这个“ContentTypeRestrictedFileField”。

例:

 class Stuff(models.Model): title = models.CharField(max_length=245) handout = ContentTypeRestrictedFileField(upload_to='uploads/', content_types=['video/x-msvideo', 'application/pdf', 'video/mp4', 'audio/mpeg', ],max_upload_size=5242880,blank=True, null=True) 

当你只想接受FileField中的特定文件types时,这些就是你必须要做的事情。

Django版本1.11中新增了用于模型字段的FileExtensionValidator ,文档位于: https : //docs.djangoproject.com/en/dev/ref/validators/#fileextensionvalidator 。

一个如何validation文件扩展名的例子:

 from django.core.validators import FileExtensionValidator from django.db import models class MyModel(models.Model): pdf_file= models.FileField(upload_to='foo/', validators=[FileExtensionValidator(allowed_extensions=['pdf'])]) 

请注意,这种方法是不安全的 。 从Django文档引用:

不要依赖文件扩展名的确认来确定文件的types。 无论文件包含什么数据,文件都可以重命名为扩展名。

还有一个新的validate_image_file_extensionhttps://docs.djangoproject.com/zh/dev/ref/validators/#validate-image-file-extension )用于validation图像扩展(使用Pillow)。

我想你会最适合使用Dominic Rodger在他的回答中指定的ExtFileField ,而Daniel Quinn提到的python-magic是最好的方法。 如果有人足够聪明,至less可以改变扩展名,那么你可以用标题来捕捉它们。

另外我会扩展这个类的一些额外的行为。

 class ContentTypeRestrictedFileField(forms.FileField): ... widget = None ... def __init__(self, *args, **kwargs): ... self.widget = forms.ClearableFileInput(attrs={'accept':kwargs.pop('accept', None)}) super(ContentTypeRestrictedFileField, self).__init__(*args, **kwargs) 

当我们用param accept =“。pdf,.txt”创build实例时,在popup文件结构为默认情况下,我们将看到带有扩展名的文件。

您可以使用下面的来限制表单中的文件types

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

您可以在设置中定义一个可接受的MIMEtypes列表,然后定义一个使用python-magic检测MIMEtypes的validation器,如果MIMEtypes不被接受,则会引发ValidationError。 在文件表单字段上设置validation器。

唯一的问题是有时MIMEtypes是application / octet-stream,它可能对应于不同的文件格式。 你们有人解决了这个问题吗?