Skip to main content
 首页 » 编程设计

python之使用 PIL 时 'JpegImageFile' 对象没有属性 '_committed' 错误

2025年05月04日17zhwl

我正在使用 PIL 压缩上传的图像 (FileField)。但是我收到一个错误,我认为这是双重保存的问题? (保存我的图像,然后保存包含图像的整个表格)。我想在保存图像时执行 commit=False 但它似乎不可行。这是我的代码:

... 
if form_post.is_valid(): 
    instance = form_post.save(commit=False) 
    instance.user = request.user 
 
if instance.image: 
    filename = instance.image 
    instance.image = Image.open(instance.image) 
    instance.image.thumbnail((220, 130), Image.ANTIALIAS) 
    instance.image.save(filename, quality=60) 
 
instance.save() 

返回 'JpegImageFile' object has no attribute '_committed' 最后一行错误 (instance.save())

有人能找出问题所在吗? - 知道我该如何解决吗?

完整回溯:

File "/Users/zorgan/Desktop/app/lib/python3.5/site-packages/django/core/handlers/exception.py" in inner 
  41.             response = get_response(request) 
 
File "/Users/zorgan/Desktop/app/lib/python3.5/site-packages/django/core/handlers/base.py" in _get_response 
  187.                 response = self.process_exception_by_middleware(e, request) 
 
File "/Users/zorgan/Desktop/app/lib/python3.5/site-packages/django/core/handlers/base.py" in _get_response 
  185.                 response = wrapped_callback(request, *callback_args, **callback_kwargs) 
 
File "/Users/zorgan/Desktop/app/lib/python3.5/site-packages/django/contrib/auth/decorators.py" in _wrapped_view 
  23.                 return view_func(request, *args, **kwargs) 
 
File "/Users/zorgan/Desktop/project/site/post/views.py" in post 
  68.                 if uploaded_file_type(instance) is True: 
 
File "/Users/zorgan/Desktop/project/site/functions/helper_functions.py" in uploaded_file_type 
  12.     f = file.image.read(1024) 
 
Exception Type: AttributeError at /post/ 
Exception Value: 'JpegImageFile' object has no attribute 'read' 

完整模型:

class Post(models.Model): 
    user = models.ForeignKey(User, blank=True, null=True) 
    title = models.TextField(max_length=95) 
    image = models.FileField(null=True, blank=True) 

和随附的 PostForm:

class PostForm(forms.ModelForm): 
    title = forms.TextInput(attrs={'placeholder': 'title'}) 
 
    class Meta: 
        model = Post 
        fields = [ 
            'user', 
            'title', 
            'image', 
        ] 

views.py

def post(request):     
    if request.user.is_authenticated(): 
        form_post = PostForm(request.POST or None, request.FILES or None) 
        if form_post.is_valid(): 
            instance = form_post.save(commit=False) 
 
            if instance.image: 
                filename = instance.image 
                instance.image = Image.open(instance.image) 
                instance.image.thumbnail((220, 130), Image.ANTIALIAS) 
                instance.image.save(filename, quality=60) 
 
            instance.save() 
 
            return HttpResponseRedirect('/home/') 
        else: 
            form_post = PostForm() 
 
        context = { 
            'form_post': form_post, 
        } 
 
        return render(request, 'post/post.html', context) 
    else: 
        return HttpResponseRedirect("/accounts/signup/") 

以下代码:

if instance.image: 
    im = Image.open(instance.image) 
    print("Filename:", im.filename) #doesn't print anything 
    thumb = im.thumbnail((220, 130), Image.ANTIALIAS) 
    thumb.save(im.filename, quality=60) 

返回一个 AttributeError:'NoneType' 对象没有属性 'save'。我相信这是因为 im.filename 没有打印任何东西。知道为什么吗?

另一种方法:

if instance.image: 
    im = Image.open(instance.image) 
    thumb = im.thumbnail((220, 130), Image.ANTIALIAS) 
    thumb_io = BytesIO() 
    thumb.save(thumb_io, im.format, quality=60) 
    instance.image.save(im.filename, ContentFile(thumb_io.get_value()), save=False) 

还返回 AttributeError :'NoneType' object has no attribute 'save',在这一行:thumb.save(thumb_io, im.format, quality =60)。不确定为什么?

请您参考如下方法:

您必须将 django 的 File 对象实例传递给 FileField.save()更改文件字段的内容。它的工作方式与其他类型的模型字段略有不同。

FieldFile.save(name, content, save=True)

This method takes a filename and file contents and passes them to the storage class for the field, then associates the stored file with the model field. If you want to manually associate file data with FileField instances on your model, the save() method is used to persist that file data.

from PIL import Image 
from django.core.files.base import ContentFile 
 
if instance.image: 
    im = Image.open(instance.image) 
    im.thumbnail((220, 130), Image.ANTIALIAS) 
    thumb_io = BytesIO() 
    im.save(thumb_io, im.format, quality=60) 
    instance.image.save(im.filename, ContentFile(thumb_io.getvalue()), save=False) 
instance.save() 

但是如果您没有使用远程文件存储后端,您可以只覆盖文件本身。该文件是在您调用 form.save() 时创建的。由于您使用的是相同的文件名和位置,因此您实际上不必触摸模型或告诉 django 您正在弄乱文件本身。

if instance.image: 
    im = Image.open(instance.image) 
    im.thumbnail((220, 130), Image.ANTIALIAS) 
    im.save(im.filename, quality=60)