如何在django ImageField中验证图像格式

Dmi*_*try 6 python django python-imaging-library

我们的项目使用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.

Ste*_*ger 5

您没有指定是否使用Django表单来上传图像,我假设它是在表单字段中执行验证.

你可以做的是创建一个子类django.forms.fields.ImageField来扩展to_python的功能.

目前在Django中执行的文件类型检查to_python看起来像这样

Image.open(file).verify()
Run Code Online (Sandbox Code Playgroud)

您的子类可能看起来像.

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
Run Code Online (Sandbox Code Playgroud)

您可能会注意到这是大多数代码,ImageField.to_python并且可能更愿意只创建一个FileField子类ImageField而不是子类化ImageField并复制其大部分功能.在这种情况下,请确保im.verify()在格式检查之前添加.

编辑:我应该指出,我没有测试过这个子类.

  • try ... except块将捕获`raise ValidationError`,此外,您可以使用`clean_field`方法的形式更轻松地完成此操作。 (2认同)