Contents:

Django图片系统


1105 浏览 5 years, 10 months

2 缩略图

版权声明: 转载请注明出处 http://www.codingsoho.com/

缩略图

有的时候,如果图片过大或者图片很多,显示原图的话,加载会非常慢,我们可以用缩略图来解决。

图片在model定义里我们用的是ImageField,我们可以继承这个类,在里面实现缩略图功能。

  • 继承ImageFieldFile的文件类为ThumbnailImageFieldFile,它默认不创建缩略图create_additional_thumbnail=False
  • 定义ThumbnailImageField,该类从ImageField继承。指定attr_classThumbnailImageFieldFile, 在该field里面重写函数__init__,替换attr_classcreate_additional_thumbnail为True,或者也可以重新定义这个class ThumbnailImageFieldFile2
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_paththumb_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里,默认的图片删除系统是不删除已上传的文件的,即使我们不做缩略图,也通过通过这个方法进行图片的同步添加和删除。