Django上传图片转WebP格式后无法保存至数据库的问题
Django上传图片转WebP并保存路径到数据库解决方案
问题根源
原代码直接将PIL的Image实例赋值给ImageField字段是错误的——ImageField需要的是媒体根目录下的相对路径或File对象,而非图像实例;同时未正确关联生成的WebP文件路径到模型字段,导致数据库未存储正确路径。
修改后的完整实现
首先确保已安装pillow库:
pip install pillow
修改Banner模型代码:
import os from PIL import Image from django.db import models # 补充你的设备尺寸选项定义 Banner_Device_Choice = [ ('desktop', '桌面端'), ('mobile', '移动端'), ] class Banner(models.Model): image = models.ImageField(upload_to='banner') device_size = models.CharField(max_length=20, choices=Banner_Device_Choice) def save(self, *args, **kwargs): # 判断是否需要执行图片转换:新增图片或已有图片被修改 is_image_changed = False if self.pk is None: is_image_changed = True else: original_banner = Banner.objects.get(pk=self.pk) if original_banner.image.path != self.image.path: is_image_changed = True if is_image_changed: # 先保存原始图片,获取完整存储路径 super().save(*args, **kwargs) # 打开原始图片并转换为WebP格式 with Image.open(self.image.path).convert('RGB') as im: # 生成WebP文件路径:替换原文件扩展名 original_ext = os.path.splitext(self.image.path)[1] webp_file_path = self.image.path.replace(original_ext, '.webp') # 保存WebP文件,可通过quality参数调整画质(1-100) im.save(webp_file_path, 'webp', quality=80) # 构造媒体根目录下的相对路径,这是ImageField存储到数据库的格式 relative_webp_path = os.path.relpath(webp_file_path, self.image.storage.location) # 更新image字段的存储路径 self.image.name = relative_webp_path # 仅更新image字段,避免触发重复转换逻辑 super().save(update_fields=['image'], *args, **kwargs) # 可选:删除原始上传的非WebP文件,清理冗余 original_file_path = self.image.path.replace(relative_webp_path, self.image.name) if os.path.exists(original_file_path): os.remove(original_file_path) else: # 图片未变化,直接保存其他字段 super().save(*args, **kwargs)
关键说明
- 转换触发逻辑:仅在图片新增或修改时执行转换,避免每次保存模型都重复处理图片
- 路径处理:基于原始图片路径生成WebP文件路径,确保文件存储在
upload_to指定的banner目录下 - 字段赋值:通过
self.image.name设置媒体根目录下的相对路径,这是DjangoImageField存储到数据库的正确格式 - 避免递归:第二次保存时使用
update_fields=['image']指定仅更新图片字段,同时通过判断逻辑跳过转换步骤,防止递归调用 - 冗余清理:可选删除原始上传的非WebP文件,减少存储空间占用
内容的提问来源于stack exchange,提问作者Manoj Kamble
相关产品推荐
相关产品推荐

