Как проверить формат изображения в django ImageField

наш проект использует Python 2.7, PIL 1.1.7 и Django 1.5.1. Существует ImageField, который работает нормально для многих форматов изображений, включая bmp, gif, ico, pnm, psd, tif и pcx. Однако требование состоит в том, чтобы разрешить только изображения png или jpg. Как это можно сделать?

Upd. Я знаю,что могу проверить расширение файла и заголовок HTTP Content-Type. Но ни один из методов не надежен. Я спрашиваю, есть ли способ проверить содержимое загруженного файла на png/jpg.

3 ответов


вы не указываете, используете ли вы форму Django для загрузки изображения, я предполагаю, что в поле формы выполняется проверка.

что вы можете сделать, это создать подкласс django.forms.fields.ImageField для расширения функциональности to_python.

проверка типа файла в настоящее время выполняется в Django в to_python выглядит так

Image.open(file).verify()

ваш подкласс может выглядеть примерно так.

class DmitryImageField(ImageField):

    def to_python(self, data):
        f = super(DmitryImageField, self).to_python(data)
        if f is None:
            return None

        try:
            from PIL import Image
        except ImportError:
            import Image

        # We need to get a file object for PIL. We might have a path or we might
        # have to read the data into memory.
        if hasattr(data, 'temporary_file_path'):
            file = data.temporary_file_path()
        else:
            if hasattr(data, 'read'):
                file = BytesIO(data.read())
            else:
                file = BytesIO(data['content'])

        try:
            im = Image.open(file)
            if im.format not in ('BMP', 'PNG', 'JPEG'):
                raise ValidationError("Unsupport image type. Please upload bmp, png or jpeg")
        except ImportError:
            # Under PyPy, it is possible to import PIL. However, the underlying
            # _imaging C module isn't available, so an ImportError will be
            # raised. Catch and re-raise.
            raise
        except Exception: # Python Imaging Library doesn't recognize it as an image
            raise ValidationError(self.error_messages['invalid_image'])

        if hasattr(f, 'seek') and callable(f.seek):
            f.seek(0)
        return f

вы можете заметить, что это большая часть код ImageField.to_python и может предпочесть просто создать подкласс FileField для использования вместо ImageField а не подклассы ImageField и дублирование большей части его функциональности. В этом случае обязательно добавьте im.verify() перед проверкой формата.

EDIT: я должен отметить, что я не тестировал этот подкласс.


вы, вероятно, захотите использовать os для этого. Из документов Python.

os.путь.splitext(путь) Разделите путь пути на пару (root, ext) таким образом, что root + ext == path, а ext пуст или начинается с точки и содержит не более одного периода. Начальные периоды базового имени игнорируются; splitext ('.cshrc') returns ('.cshrc по', "). Изменено в версии 2.6: более ранние версии могли создать пустой корень, когда единственным периодом был первый характер.

пример

import os
fileName, fileExtension = os.path.splitext('yourImage.png')

print fileName 
>>> "yourImage"

print fileExtension
>>> ".png"

поэтому, как только вы отделите ext от имени файла, вы должны просто использовать простое сравнение строк, чтобы убедиться, что это правильный формат.


можно использовать python-magic, оболочка ctype вокруг libmagic, библиотеки, используемой file на Linux.

из его doc:

>>> import magic
>>> magic.from_file("testdata/test.pdf")
'PDF document, version 1.2'
>>> magic.from_buffer(open("testdata/test.pdf").read(1024))
'PDF document, version 1.2'
>>> magic.from_file("testdata/test.pdf", mime=True)
'application/pdf'

однако этот метод просто посмотрите на mime информация. Вы все еще можете загрузить недействительный PNG с правильным mime или встроить несанкционированные данные в метаданные файла.