使用PIL压缩上传图片时遇KeyError及_committed属性缺失错误求助
问题排查与解决方案
嘿,这俩问题其实是Django结合PIL处理上传图片时的典型坑,咱们一步步拆解清楚:
1. 先说说 KeyError 为啥会出现
这个错误大概率是你在处理文件时,要么引用了request.FILES里不存在的键,要么处理完图片后没正确把新文件放回对应的键位。举个例子:如果前端表单的文件输入框name是avatar,你代码里却写成了request.FILES['profile_img'],或者你直接修改了request.FILES的结构,导致后续找不到对应的文件键,就会触发KeyError。
2. 'JpegImageFile' object has no attribute '_committed' 的核心原因
这是关键问题:Django的ImageField/FileField不认PIL的JpegImageFile对象!
Django的文件字段要求关联的必须是Django兼容的文件对象(比如InMemoryUploadedFile、TemporaryUploadedFile这类继承自django.core.files.File的类),这些对象自带Django文件系统需要的_committed属性(用来跟踪文件是否已经落地到磁盘)。而你直接把PIL处理后的图片对象赋值给模型字段,PIL对象根本没这个属性,调用instance.save()自然就报错了。
给你一个能跑的正确示例(Django场景)
下面是标准的压缩+保存流程,你可以参考调整:
from django.core.files.uploadedfile import InMemoryUploadedFile from django.http import HttpResponse, HttpResponseBadRequest from PIL import Image import io def upload_and_compress_image(request): if request.method != 'POST': return HttpResponse("Only POST requests allowed") # 先确保能正确拿到上传的文件,避免KeyError upload_field_name = "your_image_field" # 和前端input的name一致! uploaded_file = request.FILES.get(upload_field_name) if not uploaded_file: return HttpResponseBadRequest(f"请上传图片(字段名:{upload_field_name})") # 用PIL打开并压缩图片 try: img = Image.open(uploaded_file) # 示例:缩放到最大800x800,保持比例 img.thumbnail((800, 800)) except Exception as e: return HttpResponseBadRequest(f"图片处理失败:{str(e)}") # 把PIL图片转换成Django能识别的文件对象 output_buffer = io.BytesIO() # 保存到内存缓冲区,可调整quality参数控制压缩率(1-100) img.save(output_buffer, format="JPEG", quality=70) output_buffer.seek(0) # 重置缓冲区指针到开头,不然读不到内容 # 创建Django的InMemoryUploadedFile对象 compressed_file = InMemoryUploadedFile( file=output_buffer, field_name='ImageField', name=f"{uploaded_file.name.split('.')[0]}_compressed.jpg", # 自定义压缩后的文件名 content_type='image/jpeg', size=output_buffer.getbuffer().nbytes, charset=None ) # 赋值给模型并保存 from your_app.models import YourImageModel instance = YourImageModel() instance.your_image_field = compressed_file # 对应模型里的ImageField字段名 instance.save() # 现在不会报_committed错误了 return HttpResponse("图片上传并压缩成功!")
最后再划几个重点
- 永远别直接把PIL的图片对象塞给Django模型的文件字段,必须转成
InMemoryUploadedFile或者FileSystemFile这类Django认可的类型。 - 处理
request.FILES时,一定要和前端表单的name字段严格对应,不然就会踩KeyError的坑。 - 如果要支持PNG等其他格式,记得动态判断原文件格式,调整
img.save()的format参数(比如原文件是PNG就用format="PNG")。
内容的提问来源于stack exchange,提问作者Zorgan
相关产品推荐
相关产品推荐

