How can I restrict FileField
to only accept a certain type of file (video, audio, pdf, etc.) in an elegant way, server-side?
如何限制FileField只以优雅的方式接受特定类型的文件(视频、音频、pdf等),服务器端?
9 个解决方案
#1
50
One very easy way is to use a custom validator.
一个非常简单的方法是使用自定义验证器。
In your app's validators.py
:
在你的应用的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.')
Then in your models.py
:
然后在你的models.py:
from .validators import validate_file_extension
... and use the validator for your form field:
…并在表单字段中使用验证器:
class Document(models.Model):
file = models.FileField(upload_to="documents/%Y/%m/%d", validators=[validate_file_extension])
See also: How to limit file types on file uploads for ModelForms with FileFields?.
参见:如何限制带有文件字段的ModelForms在文件上传时的文件类型?
#2
15
Django in version 1.11
has a newly added FileExtensionValidator
for model fields, the docs is here: https://docs.djangoproject.com/en/dev/ref/validators/#fileextensionvalidator.
Django在1.11版本中新增了一个用于模型字段的FileExtensionValidator,文档在这里:https://docs.djangoproject.com/en/dev/ref/validators/# FileExtensionValidator。
An example of how to validate a file extension:
如何验证文件扩展名的示例:
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'])])
Note that this method is not safe. Citation from Django docs:
注意,此方法不安全。Django文档的引用:
Don’t rely on validation of the file extension to determine a file’s type. Files can be renamed to have any extension no matter what data they contain.
不要依赖对文件扩展名的验证来确定文件的类型。无论文件包含什么数据,都可以将其重命名为具有任何扩展名。
There is also new validate_image_file_extension
(https://docs.djangoproject.com/en/dev/ref/validators/#validate-image-file-extension) for validating image extensions (using Pillow).
还有新的validate_image_file_extension (https://docs.djangoproject.com/en/dev/ref/validators/# validate-imag-file -extension),用于验证图像扩展(使用Pillow)。
#3
10
There's a Django snippet that does this:
有一个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()
#4
7
First. Create a file named formatChecker.py inside the app where the you have the model that has the FileField that you want to accept a certain file type.
第一。创建一个名为formatChecker的文件。py在应用中,你有一个模型它有你想要接受的文件类型的FileField。
This is your formatChecker.py:
这是你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
Second. In your models.py, add this:
第二。在你的模型。py,添加:
from formatChecker import ContentTypeRestrictedFileField
Then instead of using 'FileField', use this 'ContentTypeRestrictedFileField'.
然后使用“ContentTypeRestrictedFileField”而不是“FileField”。
Example:
例子:
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)
Those are the things you have to when you want to only accept a certain file type in FileField.
当您只想在FileField中接受特定的文件类型时,您必须这样做。
#5
2
I think you would be best suited using the ExtFileField that Dominic Rodger specified in his answer and python-magic that Daniel Quinn mentioned is the best way to go. If someone is smart enough to change the extension at least you will catch them with the headers.
我认为你最适合使用多米尼克·罗杰在他的回答中提到的ExtFileField和丹尼尔·奎因提到的python-magic是最好的方法。如果有人足够聪明地更改了扩展名,至少您可以用header捕获他们。
#6
2
You can use the below to restrict filetypes in your Form
您可以使用下面的方法来限制表单中的文件类型。
file = forms.FileField(widget=forms.FileInput(attrs={'accept':'application/pdf'}))
#7
1
Additionally i Will extend this class with some extra behaviour.
另外,我将通过一些额外的行为来扩展这个类。
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)
When we create instance with param accept=".pdf,.txt", in popup with file structure as a default we will see files with passed extension.
当我们使用param accept=".pdf创建实例时。txt",在弹出的默认文件结构中,我们将看到文件通过了扩展名。
#8
1
You can define a list of accepted mime types in settings and then define a validator which uses python-magic to detect the mime-type and raises ValidationError if the mime-type is not accepted. Set that validator on the file form field.
您可以在设置中定义一个已接受的mime类型列表,然后定义一个验证器,该验证器使用python-magic来检测mime类型,并在不接受mime类型时引发ValidationError。在文件表单字段上设置验证器。
The only problem is that sometimes the mime type is application/octet-stream, which could correspond to different file formats. Did someone of you overcome this issue?
唯一的问题是,有时mime类型是应用程序/octet-stream,它可以对应不同的文件格式。你们有人解决过这个问题吗?
#9
0
A few people have suggested using python-magic to validate that the file actually is of the type you are expecting to receive. This can be incorporated into the validator
suggested in the accepted answer:
一些人建议使用python-magic来验证文件实际上是您期望收到的类型。这可以并入已接受的答案中所建议的验证器:
import os
import magic
from django.core.exceptions import ValidationError
def validate_is_pdf(file):
valid_mime_types = ['application/pdf']
file_mime_type = magic.from_buffer(file.read(1024), mime=True)
if file_mime_type not in valid_mime_types:
raise ValidationError('Unsupported file type.')
valid_file_extensions = ['.pdf']
ext = os.path.splitext(file.name)[1]
if ext.lower() not in valid_file_extensions:
raise ValidationError('Unacceptable file extension.')
This example only validates a pdf, but any number of mime-types and file extensions can be added to the arrays.
此示例仅验证pdf,但是可以向数组中添加任意数量的mime类型和文件扩展名。
Assuming you saved the above in validators.py
you can incorporate this into your model like so:
假设您将上面的内容保存在验证器中。py,你可以把它合并到你的模型中,比如:
from myapp.validators import validate_is_pdf
class PdfFile(models.Model):
file = models.FileField(upload_to='pdfs/', validators=(validate_is_pdf,))
#1
50
One very easy way is to use a custom validator.
一个非常简单的方法是使用自定义验证器。
In your app's validators.py
:
在你的应用的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.')
Then in your models.py
:
然后在你的models.py:
from .validators import validate_file_extension
... and use the validator for your form field:
…并在表单字段中使用验证器:
class Document(models.Model):
file = models.FileField(upload_to="documents/%Y/%m/%d", validators=[validate_file_extension])
See also: How to limit file types on file uploads for ModelForms with FileFields?.
参见:如何限制带有文件字段的ModelForms在文件上传时的文件类型?
#2
15
Django in version 1.11
has a newly added FileExtensionValidator
for model fields, the docs is here: https://docs.djangoproject.com/en/dev/ref/validators/#fileextensionvalidator.
Django在1.11版本中新增了一个用于模型字段的FileExtensionValidator,文档在这里:https://docs.djangoproject.com/en/dev/ref/validators/# FileExtensionValidator。
An example of how to validate a file extension:
如何验证文件扩展名的示例:
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'])])
Note that this method is not safe. Citation from Django docs:
注意,此方法不安全。Django文档的引用:
Don’t rely on validation of the file extension to determine a file’s type. Files can be renamed to have any extension no matter what data they contain.
不要依赖对文件扩展名的验证来确定文件的类型。无论文件包含什么数据,都可以将其重命名为具有任何扩展名。
There is also new validate_image_file_extension
(https://docs.djangoproject.com/en/dev/ref/validators/#validate-image-file-extension) for validating image extensions (using Pillow).
还有新的validate_image_file_extension (https://docs.djangoproject.com/en/dev/ref/validators/# validate-imag-file -extension),用于验证图像扩展(使用Pillow)。
#3
10
There's a Django snippet that does this:
有一个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()
#4
7
First. Create a file named formatChecker.py inside the app where the you have the model that has the FileField that you want to accept a certain file type.
第一。创建一个名为formatChecker的文件。py在应用中,你有一个模型它有你想要接受的文件类型的FileField。
This is your formatChecker.py:
这是你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
Second. In your models.py, add this:
第二。在你的模型。py,添加:
from formatChecker import ContentTypeRestrictedFileField
Then instead of using 'FileField', use this 'ContentTypeRestrictedFileField'.
然后使用“ContentTypeRestrictedFileField”而不是“FileField”。
Example:
例子:
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)
Those are the things you have to when you want to only accept a certain file type in FileField.
当您只想在FileField中接受特定的文件类型时,您必须这样做。
#5
2
I think you would be best suited using the ExtFileField that Dominic Rodger specified in his answer and python-magic that Daniel Quinn mentioned is the best way to go. If someone is smart enough to change the extension at least you will catch them with the headers.
我认为你最适合使用多米尼克·罗杰在他的回答中提到的ExtFileField和丹尼尔·奎因提到的python-magic是最好的方法。如果有人足够聪明地更改了扩展名,至少您可以用header捕获他们。
#6
2
You can use the below to restrict filetypes in your Form
您可以使用下面的方法来限制表单中的文件类型。
file = forms.FileField(widget=forms.FileInput(attrs={'accept':'application/pdf'}))
#7
1
Additionally i Will extend this class with some extra behaviour.
另外,我将通过一些额外的行为来扩展这个类。
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)
When we create instance with param accept=".pdf,.txt", in popup with file structure as a default we will see files with passed extension.
当我们使用param accept=".pdf创建实例时。txt",在弹出的默认文件结构中,我们将看到文件通过了扩展名。
#8
1
You can define a list of accepted mime types in settings and then define a validator which uses python-magic to detect the mime-type and raises ValidationError if the mime-type is not accepted. Set that validator on the file form field.
您可以在设置中定义一个已接受的mime类型列表,然后定义一个验证器,该验证器使用python-magic来检测mime类型,并在不接受mime类型时引发ValidationError。在文件表单字段上设置验证器。
The only problem is that sometimes the mime type is application/octet-stream, which could correspond to different file formats. Did someone of you overcome this issue?
唯一的问题是,有时mime类型是应用程序/octet-stream,它可以对应不同的文件格式。你们有人解决过这个问题吗?
#9
0
A few people have suggested using python-magic to validate that the file actually is of the type you are expecting to receive. This can be incorporated into the validator
suggested in the accepted answer:
一些人建议使用python-magic来验证文件实际上是您期望收到的类型。这可以并入已接受的答案中所建议的验证器:
import os
import magic
from django.core.exceptions import ValidationError
def validate_is_pdf(file):
valid_mime_types = ['application/pdf']
file_mime_type = magic.from_buffer(file.read(1024), mime=True)
if file_mime_type not in valid_mime_types:
raise ValidationError('Unsupported file type.')
valid_file_extensions = ['.pdf']
ext = os.path.splitext(file.name)[1]
if ext.lower() not in valid_file_extensions:
raise ValidationError('Unacceptable file extension.')
This example only validates a pdf, but any number of mime-types and file extensions can be added to the arrays.
此示例仅验证pdf,但是可以向数组中添加任意数量的mime类型和文件扩展名。
Assuming you saved the above in validators.py
you can incorporate this into your model like so:
假设您将上面的内容保存在验证器中。py,你可以把它合并到你的模型中,比如:
from myapp.validators import validate_is_pdf
class PdfFile(models.Model):
file = models.FileField(upload_to='pdfs/', validators=(validate_is_pdf,))