I'm using PIL to compress uploaded images(FileField
). However I'm getting an error which I believe is a problem of double saving? (saving my image, and then saving the whole form which includes the image). I wanted to perform commit=False
when I'm saving the image but it doesn't appear it's possible. Here's my code:
...
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()
returns 'JpegImageFile' object has no attribute '_committed'
error on the last line (instance.save()
)
Can someone identify the problem? - and any idea how I can fix it?
Full Traceback:
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'
Full models:
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)
and the accompanying 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/")
This following code:
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)
returns an AttributeError
: 'NoneType' object has no attribute 'save'
. I believe this is because im.filename
doesn't print anything. Any idea why?
The other method:
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)
also returns AttributeError
: 'NoneType' object has no attribute 'save'
, on this line: thumb.save(thumb_io, im.format, quality=60)
. Not sure why though?
You must pass an instance of django's File
object to FileField.save()
to change the content of a file field. It works a bit differently from other types of model fields.
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()
But if you are not using a remote file storage backend, you could just overwrite the file itself. The file was created when you called form.save()
. Since you are using the same filename and location, you don't really have to touch the model or tell django that you are messing with the file itself.
if instance.image:
im = Image.open(instance.image)
im.thumbnail((220, 130), Image.ANTIALIAS)
im.save(im.filename, quality=60)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With