Problem with Pillow image resize and save

125 views
Skip to first unread message

Daniel Grace

unread,
Oct 24, 2014, 6:37:33 PM10/24/14
to django...@googlegroups.com
Hi,
I am trying to put together some code for resizing an image and storing the resized image on the database, but I am running into some problems having struggled to find some decent examples online.  Here is what I have come up with so far, in the model:

class UserProfile(models.Model):
    user = models.OneToOneField(User)
    website = models.URLField(blank=True)
    picture = models.ImageField(upload_to='profile_images', blank=True)
    thumb = models.ImageField(upload_to='profile_images', blank=True)

.. and in the view:

def register(request):
    context = RequestContext(request)
    registered = False
    if request.method == 'POST':
        user_form = UserForm(data=request.POST)
        profile_form = UserProfileForm(data=request.POST)
        if user_form.is_valid() and profile_form.is_valid():
            user = user_form.save()
            user.set_password(user.password)
            user.save()
            profile = profile_form.save(commit=False)
            profile.user = user
            if 'picture' in request.FILES:
                profile.picture = request.FILES['picture']
                thumb = Image.open(request.FILES['picture'])
                profile.thumb = thumb.resize((200, 200), Image.ANTIALIAS)
            profile.save()
            registered = True
        else:
            print(user_form.errors, profile_form.errors)
    else:
        user_form = UserForm()
        profile_form = UserProfileForm()
    context_dict = {}
    context_dict['user_form'] = user_form
    context_dict['profile_form'] = profile_form
    context_dict['registered'] = registered
    return render_to_response('register.html', context_dict, context)

The error is as follows:
Request Method: POST
Django Version: 1.7
Exception Type: AttributeError
Exception Value:
_committed
Exception Location: C:\landy\lib\site-packages\PIL\Image.py in __getattr__, line 608

Any ideas?
Thanks

Daniel Grace

unread,
Oct 25, 2014, 10:26:18 AM10/25/14
to django...@googlegroups.com
I need to include the following steps, but I don't know how:
1. copy the 'picture' file
2. resize it (the copy)
3. save it to the upload directory
4. store it in the 'thumb' field
... continue as before and save the 'profile'.

John

unread,
Oct 25, 2014, 2:23:33 PM10/25/14
to django...@googlegroups.com
--

Daniel,

I've done something similar for a simple image manager. I have a WebImage object that holds references to an image and its thumbnail. The thumbnail is created using imagemagick's convert function when the image is updated. Extracts from models.py and admin.py shown below should give you all the clues you need.

John

#################
# models.py

from django.conf import settings
from django.db import models
from django.db.models import F, Q
import os
import uuid
import subprocess

_CONVERT_CMD = '/usr/bin/convert'
_CONVERT_THUMBNAIL_OPTS = ['-thumbnail','150x50']

# ...

class WebImage(models.Model):
  "Images that are used on the web pages. Limited to certain sizes. Can be produced by an ImageGenerator."
  def get_image_file_path(inst, filename):
    fn, ext = os.path.splitext(filename)
    filename = "%s%s" % (uuid.uuid4(), ext)
    return os.path.join(settings.MEDIA_ROOT+'wi/', filename)
 
  name = models.CharField(max_length=80,help_text="Full name of the web image")
  slug = models.SlugField(max_length=50,help_text="Slug for the web image name")
  description = models.TextField(help_text="Image description")
  img = models.ImageField(null=True,upload_to=get_image_file_path,height_field="height",width_field="width")
  img_gen = models.ForeignKey('ImageGenerator', blank=True, null=True, on_delete=models.SET_NULL)
  img_size = models.ForeignKey('ImageSize', blank=True, null=True, default=None, on_delete=models.SET_NULL)
  width = models.IntegerField(editable=False,blank=True,help_text="Width of the picture. Not editable")
  height = models.IntegerField(editable=False,blank=True,help_text="Height of the picture. Not editable")
  licensing = models.TextField(blank=True,help_text="Details of image ownership, copyright and licensing. Blank for 'same as original image'")
  created_by = models.CharField(editable=False,blank=True,max_length=80, help_text="Uploader. Not editable")
  creation_date = models.DateTimeField(editable=False,blank=True,auto_now_add=True, help_text="Date/time uploaded. Not editable")
  uploaded_by = models.CharField(editable=False,blank=True,max_length=80, help_text="Uploader. Not editable")
  upload_date = models.DateTimeField(editable=False,blank=True,auto_now_add=True, help_text="Date/time uploaded. Not editable")
  tags = TaggableManager()

  def thumb_path(self):
    return os.path.join(settings.MEDIA_ROOT+'thumb/',os.path.basename(self.img.name))

  def thumb_url(self):
    return "%sthumb/%s" % (settings.MEDIA_URL,os.path.basename(self.img.name))

  def create_thumb(self):
    args = [_CONVERT_CMD, self.img.name] + _CONVERT_THUMBNAIL_OPTS + [self.thumb_path()]
    try:
      output = subprocess.call(args)
    except subprocess.CalledProcessError, e:
      self.description = "%s\n%s\n%d" % (self.description, e.output, e.returncode)
      pass # This needs to be a logger.
    self.save()

  def thumb_field(self):
    return ('<img src="%s" />' % self.thumb_url())
  thumb_field.short_description = "Thumbnail"
  thumb_field.allow_tags = True

  def get_absolute_url(self):
    return "%swi/%s" % (settings.MEDIA_URL,os.path.split(self.img.name)[1])

  def __unicode__(self):
    return "%s (%dx%d)" % (self.name,self.width,self.height)

########################
# admin.py

class WebImageAdmin(ModelAdmin):
  def save_model(self, req, obj, form, change):
    # Add the uploader info to the object
    if not change or obj.uploaded_by == '':
      obj.uploaded_by = "%s (%s %s)" % (req.user.username, req.user.first_name, req.user.last_name)
    # And the creator info in the same manner
    if not change or obj.created_by == '':
      obj.created_by = "%s (%s %s)" % (req.user.username, req.user.first_name, req.user.last_name)
    # And save
    obj.save()
    # Create a thumbnail
    obj.create_thumb()

  list_display = ("__unicode__","img_size","thumb_field",)
  list_filter = ('img_size','width','height')
  ordering = ('name','width','height')
  prepopulated_fields = {"slug": ("name",)}
  save_on_top = True
 
  form = WebImageForm

Aliane Abdelouahab

unread,
Oct 25, 2014, 3:23:19 PM10/25/14
to django...@googlegroups.com, john-...@martinhome.org.uk
You have to send the picture editing to another process, because you will block the operation untill the image will be converted! 

John

unread,
Oct 25, 2014, 3:31:35 PM10/25/14
to django...@googlegroups.com
That's a good idea, Aliane. In my case, the server was lightly loaded, the conversion time is very short and the admin was only used by a very small number of users who were sufficiently patient.

John
--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.
To post to this group, send email to django...@googlegroups.com.
Visit this group at http://groups.google.com/group/django-users.
To view this discussion on the web visit https://groups.google.com/d/msgid/django-users/971addda-168d-43cc-aee5-c332cea9a3d6%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Aliane Abdelouahab

unread,
Oct 25, 2014, 5:37:23 PM10/25/14
to django...@googlegroups.com, john-...@martinhome.org.uk
ah, ok :)
just as another idea, you can handle the image uploads with Nginx, this will free Python from dealing static files.
Reply all
Reply to author
Forward
0 new messages