我的模型有FileField
接受图片。我用Pillow验证它们并强制执行图像格式,但我也想用适当的扩展名保存图像文件。例如,如果我上传名为foo.gif
的JPEG图像,我想将其保存为000.jpg
,其中数字是模型中的另一个字段。
我在哪里存储图像格式,以便稍后可以在我的upload_to
callable中重复使用它来生成上传路径?
class ImageField(models.FileField):
default_error_messages = {
'invalid_image': "Upload a valid image. The file you uploaded was either not an image or a corrupted image.",
'invalid_format': "Upload an image in a valid format. The supported formats are JPEG and PNG.",
}
def to_python(self, data):
f = super(ImageField, self).to_python(data)
if f is None:
return None
if hasattr(data, 'temporary_file_path'):
file = data.temporary_file_path()
elif hasattr(data, 'read'):
file = BytesIO(data.read())
else:
file = BytesIO(data['content'])
try:
image = Image.open(file)
image.verify()
if image.format not in {'PNG', 'JPEG'}:
raise ValidationError(self.error_messages['invalid_format'], code='invalid_format')
except Exception:
raise ValidationError(self.error_messages['invalid_image'], code='invalid_image')
if hasattr(f, 'seek') and callable(f.seek):
f.seek(0)
return f
class Image(models.Model):
number = models.PositiveSmallIntegerField()
image = ImageField(upload_to=self.upload_path)
def upload_path(self, instance, upload_filename):
return ???
答案 0 :(得分:1)
首先,您粘贴在上面的代码片段来自 django forms 。请注意,Django有两种字段类:模型字段和表单字段。他们的名字通常是相同的,但实施和目的完全不同。在您的示例中,您尝试使用从自定义模型字段中的表单字段复制的代码。
真正感兴趣的代码在这里:https://github.com/django/django/blob/master/django/core/files/images.py - 这是提取图像尺寸的片段。然后在此处使用Mixin类 ImageFile
: ImageFieldFile
中的https://github.com/django/django/blob/master/django/db/models/fields/files.py。然后将后者用作 ImageField
模型字段类中的属性类。
所以,你所需要的只是:
django/core/files/images.py
并对其进行修改,不仅可以提取维度,还可以提取文件类型(例如,您将此名称命名为ImageFileWithType
)。ImageFieldFile
; ImageField
类,替换其中的属性类。from your_custom_fields_module import ImageFileWithType
from django.db.models.fields import ImageFieldFile, ImageField
class ImageFieldFileWithType(ImageFileWithType, ImageFieldFile):
"""As `ImageFileWithType` mixin is at the beginning,
it overrides default mixin"""
pass
class ImageFieldWithType(ImageField):
attr_class = ImageFieldFileWithType
然后在模型中使用此模型字段!请注意,如果您使用的是南迁移,则需要特别注意处理自定义模型字段。
希望,这有帮助!
答案 1 :(得分:0)
真的,看起来你甚至不需要使用Pillow(除非你没有发布的项目更多)。您所需要的只是定义storage system然后 - 在检索时 - 访问FileField
的{{3}}。我建议使用这种方法,因为文件及其格式的99%的时间信息是通过使用文件对象本身,从文件名确定信息,或者(在极少数情况下)使用命令行魔术来找到的。 subprocess
。
无论如何,这是一个存储示例:
from django.core.files.storage import Storage
class MyStorage(Storage):
...
def get_valid_name(name):
return name.replace('gif', 'jpg')
...
这就是你可能会有点困惑的地方。 Django拥有自己的存储引擎,可以自动将文件写入MEDIA_ROOT
目录。因此,您的代码段
def upload_path(self, instance, upload_filename):
return ???
是多余的(如果您定义自己的存储,那就是;))现在它更有意义吗? django.core.files.storage.Storage可以帮助您。
答案 2 :(得分:0)
Pillow提供Image Class,其中包含有关图像的信息。 Image.format
可能是您想要的财产。
我甚至对自己进行了一些测试,看看扩展是否重要:
user@host:~/Images$ cp myimage.jpg myimage.gif
user@host:~/Images$ cp myimage.jpg myimage.txt # Extreme test!
user@host:~/Images$ python
Python 2.7.4 (default, Apr 19 2013, 18:28:01)
[GCC 4.7.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from PIL import Image
>>> im = Image.open('/home/user/Images/myimage.jpg')
>>> im.format
'JPEG'
>>> im = Image.open('/home/user/Images/myimage.gif')
>>> im.format
'JPEG'
不,不重要。看起来不错!的☺强>