Django图片系统
1105 浏览 5 years, 10 months
2 缩略图
版权声明: 转载请注明出处 http://www.codingsoho.com/缩略图
有的时候,如果图片过大或者图片很多,显示原图的话,加载会非常慢,我们可以用缩略图来解决。
图片在model定义里我们用的是ImageField
,我们可以继承这个类,在里面实现缩略图功能。
- 继承
ImageFieldFile
的文件类为ThumbnailImageFieldFile
,它默认不创建缩略图create_additional_thumbnail=False
- 定义
ThumbnailImageField
,该类从ImageField
继承。指定attr_class
为ThumbnailImageFieldFile
, 在该field里面重写函数__init__
,替换attr_class
的create_additional_thumbnail为True
,或者也可以重新定义这个classThumbnailImageFieldFile2
。
class ThumbnailImageField(ImageField):
"""
Behaves like a regular ImageField, but stores an extra (JPEG) thumbnail
image, providing FIELD.thumb_url and FIELD.thumb_path.
Accepts two additional, optional arguments: thumb_width and thumb_height,
both defaulting to 128 (pixels). Resizing will preserve aspect ratio while
staying inside the requested dimensions; see PIL's Image.thumbnail()
method documentation for details.
"""
attr_class = ThumbnailImageFieldFile
def __init__(self, thumb_width=128, thumb_height=128, add_thumb=False, *args, **kwargs):
self.thumb_width = thumb_width
self.thumb_height = thumb_height
if add_thumb:
# self.attr_class = ThumbnailImageFieldFile2
self.attr_class.create_additional_thumbnail = True
super(ThumbnailImageField, self).__init__(*args, **kwargs)
def pre_save(self, model_instance, add):
"Returns field's value just before saving."
file = super(ThumbnailImageField, self).pre_save(model_instance, add) # it will call ImageFieldFile::save
if file and not file._committed:
# Commit the file to storage prior to saving the model
file.save(file.name, file, save=False)
return file
具体保存的工作在ThumbnailImageFieldFile里面完成
处理包含了保存和删除操作。
class ThumbnailImageFieldFile(ImageFieldFile):
create_additional_thumbnail = False
def _get_thumb_path(self):
return _add_thumb(self.path)
thumb_path = property(_get_thumb_path)
def _get_thumb_url(self):
return _add_thumb(self.url)
thumb_url = property(_get_thumb_url)
def save(self, name, content, save=True):
super(ThumbnailImageFieldFile, self).save(name, content, save)
if self.create_additional_thumbnail:
img = Image.open(self.path)
img.thumbnail(
(self.field.thumb_width, self.field.thumb_height),
Image.ANTIALIAS
)
img.save(self.thumb_path, 'JPEG')
def delete(self, save=True):
if os.path.exists(self.thumb_path):
os.remove(self.thumb_path)
super(ThumbnailImageFieldFile, self).delete(save)
def _add_thumb(s):
"""
Modifies a string (filename, URL) containing an image filename, to insert
'.thumb'
"""
parts = s.split(".")
parts.insert(-1, "thumb")
if parts[-1].lower() not in ['jpeg', 'jpg']:
parts[-1] = 'jpg'
new_path = ".".join(parts)
# if not os.path.exists(new_path):
# new_path = None
return new_path
上面函数中,在添加和删除时都针对缩略图做了特别处理。
同时,还添加了两个property thumb_path
和thumb_url
, 它们会在模板里使用,用于缩略图的显示。
{% if is_initial %}
{{ initial_text }}: <a href="{{ widget.value.url }}"><img src="{% if widget.value.thumb_url %}{{widget.value.thumb_url}}{% else %}{{widget.value.url}}{% endif %}" alt="{{widget.value}}" style="max-width: 200px; max-height: 200px; border-radius: 5px;" /></a><br/>
{% if not widget.required %}
<input type="checkbox" name="{{ checkbox_name }}" id="{{ checkbox_id }}" />
<label for="{{ checkbox_id }}">{{ clear_checkbox_label }}</label>
{% endif %}<br />
{{ input_text }}:
{% endif %}
<input type="{{ widget.type }}" name="{{ widget.name }}"
{% include "django/forms/widgets/attrs.html" %} />
在模型定义时,如果要添加缩略图,我们要指定add_thumb
为True, 如果需要的话,也可以修改thumb的高低和宽度。
class Avatar(models.Model):
image = ThumbnailImageField(verbose_name=_('Image'), thumb_width=256, thumb_height=256, add_thumb=True, blank=False, null=False, upload_to=upload_avatar)
最终效果图如下:
在django里,默认的图片删除系统是不删除已上传的文件的,即使我们不做缩略图,也通过通过这个方法进行图片的同步添加和删除。