You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django上传图片时同步生成50%比例缩略图的实现问题

Django单次上传同时保存原图和缩略图解决方案

问题核心

  1. pre_save阶段原图还未写入磁盘,调用instance.link.path获取路径会报错
  2. 直接在post_save中调用save()会重复触发信号,导致无限循环保存

方案1:序列化器create方法中直接处理(最推荐)

将缩略图生成逻辑集中放在序列化器的create方法中,直接读取内存中的上传文件生成缩略图,无需依赖信号,一次数据库写入即可完成原图和缩略图的保存。

代码实现

首先导入依赖:

from PIL import Image
from io import BytesIO
from django.core.files import File

修改UserPhotoSerializer的create方法:

class UserPhotoSerializer(serializers.ModelSerializer):
    class Meta:
        model = UserPhoto
        fields = '__all__'

    def create(self, validated_data):
        # 提取上传的原图文件
        origin_image = validated_data.get('link')
        if origin_image:
            # 直接从内存读取原图生成缩略图
            img = Image.open(origin_image)
            width, height = img.size
            # 缩放为原图50%尺寸
            resized_img = img.resize((int(width / 2), int(height / 2))).convert('RGB')
            blob = BytesIO()
            # 保存缩略图到内存,可自行调整quality参数控制画质
            resized_img.save(blob, 'JPEG', quality=85)
            # 构造缩略图文件对象
            mini_file = File(blob, name=f'mini_{origin_image.name}')
            validated_data['mini_link'] = mini_file
        validated_data["user"] = self.context['request'].user.User_userbase
        # 一次创建操作同时保存原图和缩略图
        return UserPhoto.objects.create(**validated_data)

方案2:post_save信号处理(需避免无限循环)

如果需要保留信号的实现方式,可通过created判断+update_fields参数规避循环问题:

代码实现

修改信号逻辑:

@receiver(post_save, sender=UserPhoto)
def create_mini_photo(sender, instance, created, **kwargs):
    # 仅首次创建实例且无缩略图时执行逻辑
    if created and not instance.mini_link and instance.link:
        # 此时原图已落地磁盘,可正常读取路径
        img = Image.open(instance.link.path)
        width, height = img.size
        resized_img = img.resize((int(width / 2), int(height / 2))).convert('RGB')
        blob = BytesIO()
        resized_img.save(blob, 'JPEG', quality=85)
        # save参数设为False,先不触发保存
        instance.mini_link.save(f'mini_{instance.link.name}', File(blob), save=False)
        # 仅更新缩略图字段,避免全字段保存再次触发信号循环
        instance.save(update_fields=['mini_link'])

注意事项

  • 需提前安装Pillow依赖:pip install pillow
  • 若需要支持PNG透明图,可将convert('RGB')移除,保存格式改为PNG
  • 确保ImageField配置的upload_to对应目录拥有写入权限

内容的提问来源于stack exchange,提问作者hasaneyldrm

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 05:39:01