Как ограничить типы файлов при загрузке файлов для ModelForms с FileFields? - PullRequest
20 голосов
/ 24 июня 2011

Моя цель - ограничить FileField в Django ModelForm PDF-файлами и документами Word.Все ответы, которые я погуглил, касаются создания отдельного обработчика файлов, но я не уверен, как это сделать в контексте ModelForm.Есть ли в файле settings.py параметр, который я могу использовать для ограничения типов загружаемых файлов?

Ответы [ 6 ]

43 голосов
/ 12 января 2012

Создайте метод проверки, например:

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])

Кроме того, вместо того, чтобы вручную устанавливать, какие расширения позволяет ваша модель, вы должны создать список в файле setting.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!')
19 голосов
/ 04 июня 2015

Проверка с расширением имени файла не является согласованным способом.Например, я могу переименовать файл picture.jpg в файл picture.pdf, и проверка не вызовет ошибку.

Лучший способ - проверить тип содержимого файла.

Метод проверки

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])
5 голосов
/ 28 апреля 2017

Более простой способ сделать это, как показано ниже в вашей форме

file = forms.FileField(widget=forms.FileInput(attrs={'accept':'application/pdf'}))
4 голосов
/ 04 июля 2016

Для более общего использования я написал небольшой класс ExtensionValidator, который расширяет встроенный в Django 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)

Теперь вы можете определить валидатор, встроенный в поле, например:

my_file = models.FileField('My file', validators=[ExtensionValidator(['pdf', 'doc', 'docx'])])
3 голосов
/ 10 февраля 2016

Я использую что-то в этом духе (обратите внимание, для этого требуется «pip install filemagic» ...):

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.')

Возможно, вы также включите в него предыдущие примеры - например, также проверьтерасширение / загруженный тип (который может быть скорее первичной проверкой, чем магическим.) Это все еще не надежно - но это лучше, поскольку оно больше полагается на данные в файла, а не на заголовки, предоставленные браузером.

Примечание. Это функция валидатора, которую вы хотите добавить в список валидаторов для модели FileField.

0 голосов
/ 24 июня 2011

Я справляюсь с этим, используя метод clean_ [your_field] в ModelForm.Вы можете установить список допустимых расширений файлов в settings.py для проверки в вашем чистом методе, но нет ничего встроенного в settings.py для ограничения типов загрузки.

Например, Django-Filebrowser беретподход к созданию списка допустимых расширений файлов в settings.py.

Надеюсь, что вам это поможет.

...