Django/PIL - 在上传图像时保存缩略图版本

use*_*875 15 django image thumbnails python-imaging-library pillow

这是我的forms.py:

class UploadImageForm(forms.ModelForm):
    class Meta:
        model = UserImages
        fields = ['photo']
Run Code Online (Sandbox Code Playgroud)

这是我的models.py:

class UserImages(models.Model):
    user = models.ForeignKey(User)
    photo = models.ImageField(upload_to=get_file_path)
Run Code Online (Sandbox Code Playgroud)

这是我的看法:

def uploadImageView(request):
    if request.method == 'POST':
        form = UploadImageForm(request.POST, request.FILES)
        if form.is_valid():
            instance = form.save(commit=False)
            instance.user = request.user
            instance.save()
            return redirect('/')
    else:
        form = UploadImageForm()

    return render(request, 'uploadImagePage.html', {'uploadImageForm': form})
Run Code Online (Sandbox Code Playgroud)

但这只会保存正在上传的图像.如何保存图像的缩略图版本以及具有完全相同名称的图像的缩略图版本,除了后面带有"thumbail"字样?

我读过的教程说我可以做

im = Image.open(infile)
im.thumbnail(size, Image.ANTIALIAS)
Run Code Online (Sandbox Code Playgroud)

获取缩略图但在我的情况下,图像甚至还没有保存.

xjt*_*ian 16

要执行此操作,您应该ImageField为当前UserImages模型添加一个新的以保存缩略图,然后覆盖您save创建的方法并在保存完整图像后保存缩略图.

我已经从我的一个项目中调整了以下代码片段,我完全确定这将完全按照您的需要执行:

from cStringIO import StringIO
import os

from django.db import models
from django.core.files.base import ContentFile
from django.core.files.storage import default_storage as storage

from PIL import Image

# Thumbnail size tuple defined in an app-specific settings module - e.g. (400, 400)
from app.settings import THUMB_SIZE

class Photo(models.Model):
    """
    Photo model with automatically generated thumbnail.
    """
    photo = models.ImageField(upload_to='photos')
    thumbnail = models.ImageField(upload_to='thumbs', editable=False)

    def save(self, *args, **kwargs):
        """
        Make and save the thumbnail for the photo here.
        """
        super(Photo, self).save(*args, **kwargs)
        if not self.make_thumbnail():
            raise Exception('Could not create thumbnail - is the file type valid?')

    def make_thumbnail(self):
        """
        Create and save the thumbnail for the photo (simple resize with PIL).
        """
        fh = storage.open(self.photo.name, 'r')
        try:
            image = Image.open(fh)
        except:
            return False

        image.thumbnail(THUMB_SIZE, Image.ANTIALIAS)
        fh.close()

        # Path to save to, name, and extension
        thumb_name, thumb_extension = os.path.splitext(self.photo.name)
        thumb_extension = thumb_extension.lower()

        thumb_filename = thumb_name + '_thumb' + thumb_extension

        if thumb_extension in ['.jpg', '.jpeg']:
            FTYPE = 'JPEG'
        elif thumb_extension == '.gif':
            FTYPE = 'GIF'
        elif thumb_extension == '.png':
            FTYPE = 'PNG'
        else:
            return False    # Unrecognized file type

        # Save thumbnail to in-memory file as StringIO
        temp_thumb = StringIO()
        image.save(temp_thumb, FTYPE)
        temp_thumb.seek(0)

        # Load a ContentFile into the thumbnail field so it gets saved
        self.thumbnail.save(thumb_filename, ContentFile(temp_thumb.read()), save=True)
        temp_thumb.close()

        return True
Run Code Online (Sandbox Code Playgroud)

  • 在`make_thumbnail`中抛出异常而不是返回False不是更好吗?这样,您可以知道异常的确切原因,而不是通用异常消息 (2认同)

小智 15

基于xjtian的回答.这适用于Python 3:

import os.path
from PIL import Image
from io import BytesIO
from django.core.files.base import ContentFile
from .my_app_settings import THUMB_SIZE    

class Photo(models.Model):
    photo = models.ImageField(upload_to='photos')
    thumbnail = models.ImageField(upload_to='thumbs', editable=False)

    def save(self, *args, **kwargs):

        if not self.make_thumbnail():
            # set to a default thumbnail
            raise Exception('Could not create thumbnail - is the file type valid?')

        super(Photo, self).save(*args, **kwargs)

    def make_thumbnail(self):

        image = Image.open(self.photo)
        image.thumbnail(THUMB_SIZE, Image.ANTIALIAS)

        thumb_name, thumb_extension = os.path.splitext(self.photo.name)
        thumb_extension = thumb_extension.lower()

        thumb_filename = thumb_name + '_thumb' + thumb_extension

        if thumb_extension in ['.jpg', '.jpeg']:
            FTYPE = 'JPEG'
        elif thumb_extension == '.gif':
            FTYPE = 'GIF'
        elif thumb_extension == '.png':
            FTYPE = 'PNG'
        else:
            return False    # Unrecognized file type

        # Save thumbnail to in-memory file as StringIO
        temp_thumb = BytesIO()
        image.save(temp_thumb, FTYPE)
        temp_thumb.seek(0)

        # set save=False, otherwise it will run in an infinite loop
        self.thumbnail.save(thumb_filename, ContentFile(temp_thumb.read()), save=False)
        temp_thumb.close()

        return True
Run Code Online (Sandbox Code Playgroud)

  • 这是否意味着*每次*调用保存时都会生成缩略图,即使“照片”未更改(例如,如果模型有额外的字段并且您想更新这些字段)? (2认同)

Luc*_*uca 0

如果您不想从头开始实施解决方案,我建议您使用名为sorl-thumbnail的 django 应用程序