提问者:小点点

ImageField保存后制作缩略图


我想在Imagefield模型保存后制作上传图像的缩略图。此时我收到了引发异常错误:无法创建缩略图-文件类型有效吗?”。你们能帮我如何让它工作吗?

models.py

from django.contrib.auth.models import User
from django.db import models
from PIL import Image as Img


class Image(models.Model):
    img_owner = models.ForeignKey(User, on_delete=models.CASCADE, default=User)
    image = models.ImageField(null=True, blank=False)
    thumbnail = models.ImageField(upload_to="thumbs", editable=False)
    date_added = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ["-date_added"]

    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(Image, self).save(*args, **kwargs)

    def make_thumbnail(self):
        size = 128, 128

        im = Img.open(self.image)
        im.thumbnail(size)
        im.save(self.image.name + ".thumbnail", "PNG")

seralizers.py

from rest_framework import serializers

from .models import Image


class ImageSerializer(serializers.ModelSerializer):
    author = serializers.ReadOnlyField(source="img_owner.username")
    thumbnail = serializers.ReadOnlyField()

    class Meta:
        model = Image
        fields = ["url", "author", "img_owner", "image", "thumbnail", "date_added"]

views.py

from rest_framework import permissions, viewsets

from .models import Image
from .serializers import ImageSerializer


class ImageViewSet(viewsets.ModelViewSet):
    queryset = Image.objects.all()
    serializer_class = ImageSerializer
    permission_classes = [permissions.IsAuthenticated]

    """
    Bellow definition overrides queryset and filter images by loged user.
    """

    def get_queryset(self):
        user = self.request.user
        return Image.objects.filter(img_owner=user)

编辑:我设法用下面的代码在models.py做缩略图,但是我现在在 /images/得到一个ValueError,缩略图属性没有与之关联的文件。第二个问题我的缩略图保存在主项目目录而不是媒体文件夹中。

新models.py

from django.contrib.auth.models import User
from django.db import models
# from main.settings import MEDIA_ROOT
from PIL import Image as Img


class Image(models.Model):
    img_owner = models.ForeignKey(User, on_delete=models.CASCADE, default=User)
    image = models.ImageField(null=True, blank=False)
    thumbnail = models.ImageField(upload_to="tumbs", editable=False)
    date_added = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ["-date_added"]

    def save(
        self, force_insert=False, force_update=False, using=None, update_fields=None
    ):
        if not self.image:
            self.thumbnail = None
        else:
            size = 128, 128

            im = Img.open(self.image)
            im.thumbnail(size)
            im.save("thumb_" + self.image.name, "PNG")

        super(Image, self).save(force_insert, force_update, using, update_fields)

共1个答案

匿名用户

请注意,它会在每次保存()时创建缩略图,请考虑在它之前添加另一个检查

from django.contrib.auth.models import User
from django.db import models
from django.conf import settings  # it's the correct way to import settings
from PIL import Image as Img
from pathlib import Path


class Image(models.Model):
    img_owner = models.ForeignKey(User, on_delete=models.CASCADE, default=User)
    image = models.ImageField(null=True, blank=False)
    thumbnail = models.ImageField(upload_to="tumbs", editable=False)
    date_added = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ["-date_added"]  # it's not recommended to set ordering at model level.

    def save(self, *args, **kwargs):
        if not self.image:
            self.thumbnail = None  # note, this will not delete the file
        else:
            size = 128, 128

            im = Img.open(self.image)
            im.thumbnail(size)
            name = Path(self.image.name)
            # omit Path() if MEDIA_ROOT is already a Path object
            thb_path = Path(settings.MEDIA_ROOT) / f"thumb_{name.stem}.png" 
            self.thumbnail = thb_path.name  # it's should be relative path
             
            im.save(thb_path, "PNG")  # if it doesn't like Path, str() it

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