当图像上传到django时生成缩略图

当图像上传到django时生成缩略图,django,python-3.x,django-rest-framework,Django,Python 3.x,Django Rest Framework,我有一个网站,每天都会上传多张大尺寸的图片,因为大尺寸需要时间,所以我想在上传图片时生成缩略图: class Image(models.Model): license_type = ( ('Royalty-Free','Royalty-Free'), ('Rights-Managed','Rights-Managed') ) image_number = models.CharField(default=r

我有一个网站,每天都会上传多张大尺寸的图片,因为大尺寸需要时间,所以我想在上传图片时生成缩略图:

class Image(models.Model):
      license_type = (
    ('Royalty-Free','Royalty-Free'),
    ('Rights-Managed','Rights-Managed')
                         )
      image_number = models.CharField(default=random_image_number,max_length=12,unique=True)
      title = models.CharField(default=random_image_number,max_length = 100)
      image = models.ImageField(upload_to = 'image' , default = 'demo/demo.png')
      thumbnail = models.ImageField(upload_to='thumbs', editable=False)
      category = models.ForeignKey('Category', null=True, blank=True, on_delete=models.CASCADE)
      shoot = models.ForeignKey(ImageShoot, on_delete=models.CASCADE, related_name='Image', null=True,blank=True)
      image_keyword = models.TextField(max_length=1000)
      credit = models.CharField(max_length=150, null=True)
      location = models.CharField(max_length=100, null=True)
      license_type = models.CharField(max_length=20,choices=license_type, default='')
      uploaded_at = models.TimeField(auto_now_add=True)

      def __str__(self):
          return self.title

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

          super(Image, self).save(*args, **kwargs)
          if not self.make_thumbnail():
             raise Exception('Could not create thumbnail - is the file type valid?')

      def make_thumbnail(self):
          fh = storage.open(self.Image.name)
          try:
             image = PILImage.open(fh)
          except:
             return False
          image.thumbnail((400,400),PILImage.ANTIALIAS)
          fh.close()
          thumb_name, thumb_extension = os.path.splitext(self.Image.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
admin.py:

@admin.register(Image)
class ImageAdmin(admin.ModelAdmin):
      readonly_fields=['image_number','uploaded_at']
      fields = ['title','image_number','shoot','category',
         'image','image_keyword','credit','license_type','location','uploaded_at']
现在是错误:

string argument expected, got 'bytes'
回溯:

File "/home/tboss/Desktop/environment/live/backend/venv/lib/python3.7/site-packages/PIL/JpegImagePlugin.py", line 779, in _save
ImageFile._save(im, fp, [("jpeg", (0, 0) + im.size, 0, rawmode)], bufsize)
File "/home/tboss/Desktop/environment/live/backend/venv/lib/python3.7/site-packages/PIL/ImageFile.py", line 513, in _save
fp.write(d)
TypeError: string argument expected, got 'bytes'
 File "/home/tboss/Desktop/environment/live/backend/venv/lib/python3.7/site-packages/PIL/TiffImagePlugin.py", line 319, in __init__
  if isinstance(value, Fraction):
 File "/home/tboss/Desktop/environment/live/backend/venv/lib/python3.7/abc.py", line 139, in __instancecheck__
 return _abc_instancecheck(cls, instance)
当我使用BytesIO时:

我得到这个错误:

maximum recursion depth exceeded in comparison
回溯:

File "/home/tboss/Desktop/environment/live/backend/venv/lib/python3.7/site-packages/PIL/JpegImagePlugin.py", line 779, in _save
ImageFile._save(im, fp, [("jpeg", (0, 0) + im.size, 0, rawmode)], bufsize)
File "/home/tboss/Desktop/environment/live/backend/venv/lib/python3.7/site-packages/PIL/ImageFile.py", line 513, in _save
fp.write(d)
TypeError: string argument expected, got 'bytes'
 File "/home/tboss/Desktop/environment/live/backend/venv/lib/python3.7/site-packages/PIL/TiffImagePlugin.py", line 319, in __init__
  if isinstance(value, Fraction):
 File "/home/tboss/Desktop/environment/live/backend/venv/lib/python3.7/abc.py", line 139, in __instancecheck__
 return _abc_instancecheck(cls, instance)
RecursionError:比较中超出了最大递归深度


我目前正在上传来自管理员的图片,但也将使用drf。目前它没有创建缩略图,正如评论中所说,您可以使用base64编码图像。为此,首先将缩略图字段更改为以下内容:

thumbnail = models.CharField(max_length=2000, blank=True, null=True)
然后,重写模型保存方法并添加以下代码:

def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
    if not self.image:
        self.thumbnail = None
    else:
        thumbnail_size = 50, 50
        data_img = BytesIO()
        tiny_img = Image.open(self.image)
        tiny_img.thumbnail(thumbnail_size)
        tiny_img.save(data_img, format="BMP")
        tiny_img.close()
        try:
            self.thumbnail = "data:image/jpg;base64,{}".format(
                base64.b64encode(data_img.getvalue()).decode("utf-8")
            )
        except UnicodeDecodeError:
            self.blurred_image = None

    super(Image, self).save(force_insert, force_update, using, update_fields)
您可以更改缩略图大小变量以符合您的需要。 最后,将以下内容添加到导入部分:

import base64
from io import BytesIO

不要忘记运行makemigrations和migrate命令!如果您有任何问题,请告诉我。

您是否覆盖了模型的save()方法并调用了“make_thumbnail”?是的,请查看编辑您是否在日志中看到此异常无法创建缩略图-文件类型有效吗?“能否以正确的方式缩进代码?不清楚保存缩略图的代码是否在
def make_thumboil()
方法中正确缩进。我已经正确缩进了我得到的缩略图字段如下:image/jpg;base64,qk2eegaaaaaaaaaaaaaaaaaaaaaaaaaaaaamgaaab8aabababagaaaaaggsaadedgaaxa4aaaaaaaaaaaaaa但我如何将其转换为图像这是图像。你可以用html显示,但当我尝试解码时,得到一些随机字符,但缩略图的大小仍然是大约340pk的3mb图像。你能推荐一些压缩缩略图图像的方法吗?因为加载需要时间。你可以检查此链接中的base64图像。你尝试过减小缩略图大小吗?