0

When working with manual file uploads, do I need to place the file in the final location before saving it to the model? Or, does the model move the file at some point? If I do need to place it myself, why do I need the upload_to param in the model field? That seems like I would have to keep parity with the upload_to param and the logic I'm using to copy it.

I think I'm just confused. Can someone help me do this right?

My form gets in image url from the web:

class ProductForm(ModelForm):    
    main_image_url = forms.URLField()
    # etc...

My view retrieves it, checks it, and makes a thumbnail:

main_img_temp = NamedTemporaryFile(delete=True)
main_img_temp.write(urllib2.urlopen(main_image_url).read())
main_img_temp.flush()

img_type = imghdr.what(main_img_temp.name)
if not img_type:
    errors = form._errors.setdefault("main_image_url", ErrorList())
    errors.append(u"Url does not point to a valid image")
    return render_to_response('add_image.html', {'form':form}, context_instance=RequestContext(request))

# build a temporary path name
filename = str(uuid.uuid4())
dirname  = os.path.dirname(main_img_temp.name)
full_size_tmp  = os.path.join(dirname, filename+'_full.jpg')
thumb_size_tmp = os.path.join(dirname, filename+'_thumb.jpg')

shutil.copy2(main_img_temp.name, full_size_tmp)
shutil.copy2(main_img_temp.name, thumb_size_tmp)

# build full size and thumbnail
im = Image.open(full_size_tmp)
im.thumbnail(full_image_size, Image.ANTIALIAS)
im.save(full_size_tmp, "JPEG")

im = Image.open(thumb_size_tmp)
im.thumbnail(thumb_image_size, Image.ANTIALIAS)
im.save(thumb_size_tmp, "JPEG")

# close to delete the original temp file
main_img_tmp.close()


### HERE'S WHERE I'M STUCK. This doesn't move the file... ####
main_image = UploadedImage(image=full_size_tmp, thumbnail=thumb_size_tmp)
main_image.save()

In my models, I've got an UploadedImage model that has the basic fields:

class UploadedImage(models.Model):
    image = models.ImageField(upload_to='uploads/images/%Y/%m/%d/full')
    thumbnail = models.ImageField(upload_to='uploads/images/%Y/%m/%d/thumb/')
Scott
  • 3,204
  • 3
  • 31
  • 41

2 Answers2

0

Normally, when you save the model, it writes the files to the location that points upload_to. It handles that by itself so you won't need to do it manually.

Here you are writing the file to a temp, moving it after and a lot of things that can be done automatically. Check the answer to this question where he also uses urllib to get an image and save it into the db.

Note that you can pass a buffer in memory to create a FileField or ImageField which be suitable to do the logic for the thumbnail. Also you may consider using django-thumbnails for this purposes. It's a good library.

Hope this helps!

Community
  • 1
  • 1
Paulo Bu
  • 29,294
  • 6
  • 74
  • 73
  • Thank you for jumping in. I'll look into condensing this and handing it an in-memory object. – Scott May 23 '13 at 18:28
0

Answered My Own Question...

When I passed the path to the ImageField in the model, I was just handing it a path. I see now that to invoke all the storage handling built in to Django, you have to hand it a File object. This was enough to make it copy to the upload_to path:

from django.core.files import File

main_image = UploadedImage(image=File(open(full_size_tmp)), thumbnail=File(open(thumb_size_tmp)), creator=request.user)
main_image.save()
Scott
  • 3,204
  • 3
  • 31
  • 41