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

时间:2018-03-12 02:04:02

标签: python django python-imaging-library

我正在使用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' object has no attribute '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)。不确定为什么呢?

1 个答案:

答案 0 :(得分:6)

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

  

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

     

此方法获取文件名和文件内容并将其传递给   该字段的存储类,然后将存储的文件与   模型领域。如果要手动关联文件数据   模型上的FileField实例,save()方法用于   保留该文件数据。

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.get_value()), 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)