Как я могу ограничить FileField
только тем, что вы принимаете только определенный тип файла (видео, аудио, pdf и т.д.), на стороне сервера?
Принимать только определенный тип файла в FileField, на стороне сервера
Ответ 1
Один очень простой способ - использовать пользовательский валидатор.
В приложении 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
... и используйте валидатор для вашего поля формы:
class Document(models.Model):
file = models.FileField(upload_to="documents/%Y/%m/%d", validators=[validate_file_extension])
Смотрите также: Как ограничить типы файлов при загрузке файлов для ModelForms с помощью FileFields?.
Ответ 2
Там фрагмент 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()
Ответ 3
Во-первых. Создайте файл с именем 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
Во-вторых. В вашем файле 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.
Ответ 4
Django в версии 1.11
имеет недавно добавленные поля FileExtensionValidator
для модели, документы находятся здесь: https://docs.djangoproject.com/en/dev/ref/validators/#fileextensionvalidator.
Пример проверки расширения файла:
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 docs:
Не полагайтесь на проверку расширения файла для определения файлов тип. Файлы можно переименовать, чтобы иметь любое расширение независимо от того, какие данные они содержат.
Существует также новый validate_image_file_extension
(https://docs.djangoproject.com/en/dev/ref/validators/#validate-image-file-extension) для проверки расширений изображений (с помощью Pillow).
Ответ 5
Я думаю, вам лучше всего подойти, используя ExtFileField, который указал Доминик Роджер в своем ответе, и python-magic, о котором упоминал Даниэль Куинн, - лучший способ пойти. Если кто-то достаточно умный, чтобы изменить расширение, по крайней мере, вы поймаете их с заголовками.
Ответ 6
Вы можете использовать ниже, чтобы ограничить типы файлов в своей форме
file = forms.FileField(widget=forms.FileInput(attrs={'accept':'application/pdf'}))
Ответ 7
Кроме того, я продолжу этот класс с дополнительным поведением.
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)
Когда мы создаем экземпляр с параметром accept = ". pdf,.txt", в popup с файловой структурой по умолчанию мы увидим файлы с переданным расширением.
Ответ 8
Вы можете определить список принятых типов mime в настройках, а затем определить валидатор, который использует python-magic для обнаружения типа mime и повышает ValidationError, если тип mime не принят. Установите этот валидатор в поле формы файла.
Единственная проблема заключается в том, что иногда типом mime является application/octet-stream, который может соответствовать различным форматам файлов. Кто-то из вас преодолел эту проблему?
Ответ 9
Несколько человек предложили использовать python-magic, чтобы проверить, действительно ли файл имеет тип, который вы ожидаете получить. Это можно включить в validator
, предложенный в принятом ответе:
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.')
В этом примере проверяется только PDF, но любое количество типов mime и расширений файлов может быть добавлено в массивы.
Предполагая, что вы сохранили вышеуказанное в validators.py
, вы можете включить это в свою модель следующим образом:
from myapp.validators import validate_is_pdf
class PdfFile(models.Model):
file = models.FileField(upload_to='pdfs/', validators=(validate_is_pdf,))