Django ImageField 文件保存时处理图像(剪切,再次上传,旋转等)
Posted Jason_WangYing
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django ImageField 文件保存时处理图像(剪切,再次上传,旋转等)相关的知识,希望对你有一定的参考价值。
方法一:save时处理
使用Django的ImageField可以方便地生成图像字段,但DJANGO并没有提供相应的方法在图像文件上传时对图像进行处理,如图像裁剪,生成缩略图,在网上的找到的方法都是覆盖Model的save方法,如:
class Photo(models.Model):
photo_file = models.ImageField(verbose_name=u'文件',upload_to='album/photos/%Y/%m/%d',max_length=255)
descript = models.TextField(verbose_name=u"描述",blank=True)
def save(self, force_insert=False, force_update=False):
filename = self.photo_file.path
img = Image.open(filename)
#进行图像处理
....
....
super(Photo,self).save(force_insert, force_update)
特殊说明:
- self.photo_file.path这里返回的路径有问题,丢失了model里面的upload_to里面的路径,我找了半天也没找到原因,返回的绝对路径就是丢失了这部分
- 我实际项目用的是相对路径,这里说明下,我刚开始是这样用的open('/media/album/photos/%Y/%m/%d'),结果发现怎么调用都是提示无此文档,我自己看了半天没找到问题,吃了个饭回来,看了眼发现是多了'/'在media前面,去掉即可
- 我还发现了个问题,就是如果不调用save,图片是以数据流的形式存在内存中,没有写入文件,调用save后才写入文件
- 我这里获取文件内容后还需要再次上传到微信的素材里面,获取素材id和url,再次存储到数据库里面,所以我是先save再save(update_fields='需要更新的字段'),如果再次save的话,默认是如果有数据更新所有数据,没有数据创建数据。
def save(self, force_insert=False, force_update=False, using=None,update_fields=None):
# 永久素材上传,获取media_id
if self.images:
temp = 'media/img/'+str(self.images)
super().save()
res = wechat_check.upload_add_media_of_image(temp)
self.image_weixinid = res['media_id']
self.url = res["url"]
super().save(update_fields=['image_weixinid','url'])
else:
# 没有图片,无需上传
super().save()
上述方法可以在Model保存时获取ImageField的文件,采用PIL进行处理,但该方法有个缺点,就是当对descript字段进行修改更新时,save 方法被调用,将重新对图像进行处理,加重服务器负载.
方法二:封装类,给model.ImageField类再次封装,我们创建model时用新封装的类,在封装的类中,也是在save时修改数据
通过对Django代码的分析,采用定制ImageField的方法实现了同样功能并解决上述例子存在的缺陷:
继承ImageField生成新的图像字段类,用新的save方法覆盖ImageField的save方法,但ImageField对文件操作的方法大部分来自其父类FileField和ImageFieldFile:
#django/db/models/fields/files.py
class ImageField(FileField):
attr_class = ImageFieldFile
def __init__(self, verbose_name=None, name=None, width_field=None, height_field=None, **kwargs):
....
....
ImageField本身并不进行文件得理,要覆盖ImageField的save方法,需要先从ImageFieldFile下手,定义新的ImageFieldFile:
#生成用像类型,重载ImageField的SAVE事件,实现图像尺寸调整及自动生成缩略图
from django.db.models.fields.files import ImageFieldFile,FieldFile,FileField
class NewImageFieldFile(ImageFieldFile):
def save(self, name, content, save=True):
# Repopulate the image dimension cache.
temp_file = tempfile.TemporaryFile()
f = StringIO.StringIO(content.read())
image = Image.open(f)
#取得指定的图像最大尺寸
max_width,max_height = self.field.max_width,self.field.max_height
#进行图像处理...
....
image.save(temp_file,'JPEG')
temp_file.seek(0)
content2 = ContentFile(temp_file.read())
content.close()
temp_file.close()
super(NewImageFieldFile, self).save(name, content2, save)
#生成新的ImageField
class NewImageField(models.ImageField):
attr_class = NewImageFieldFile
def __init__(self, verbose_name=None, name=None, width_field=None, height_field=None,thumbnail_path=None,max_size=(600,600),**kwargs):
self.width_field, self.height_field = width_field, height_field
self.thumbnail_path = thumbnail_path
self.max_width,self.max_height = max_size[0], max_size[1]
models.ImageField.__init__(self, verbose_name, name, **kwargs)
修改class Photo,使用新的图像字段类:
class Photo(models.Model):
photo_file = models.NewImageField(verbose_name=u'文件',upload_to='album/photos/%Y/%m/%d',max_length=255,max_size=(1024,800))
descript = models.TextField(verbose_name=u"描述",blank=True)
以上是关于Django ImageField 文件保存时处理图像(剪切,再次上传,旋转等)的主要内容,如果未能解决你的问题,请参考以下文章
将通过 ajax 上传的文件保存到 Django 模型 ImageField