Press enter to see results or esc to cancel.

Downloading and Saving Image to ImageField in Django

Finding a way to programmatically save images to a Django model has been a real pain in the rear. There is almost no comprehensive documentation on simply associating an image you want to download to a model’s ImageField, and even if you’re able to overcome that hurdle there is a lot of mess to deal with if you want to verify that you’re saving an actual image, and not a corrupt image at that. End frustration.

Here is some code that can be used to

  • download an image from a URL
  • verify that it is actually a non-corrupt image
  • save the image to Django’s media folder
  • and then associate that image to a model Class using Django’s ImageField

Most of the examples I found save the image to a temp folder, check the image there, then move it to a public folder once it’s verified. I want to do all my file checks entirely in memory – without writing – before choosing whether or not to save the downloaded image.

Just about all of this is going to happen in the models.py, and very little is going to happen in whatever script or view wants to download and save the image. Sorry for the squeezed code and all the line-breaks…need to move off of WordPress.

The first trick is understanding how to save an image to the Django model. In this case, the image file doesn’t exist yet (it’s on another server), so if we try to save, there is no image to save. When we redefine/intercept the save method, we essentially cut the save method off and perform a couple steps first: 1) use the external URL that is passed to save() to request the image 2) take the server’s response and make sure it’s an image 3) if it is save it to our own server 4) assign the image we just saved to the ImageField, and then we essentially let save() continue. If the image isn’t valid, we don’t populate the ImageField and we let save() continue so that Product can still be saved. You could just as easily do something more elegant, like create a CharField for an external image’s URL and have the save method read from that, avoiding the need to pass a parameter to save(). It’s up to you, but all the parts should be there.

Now anytime you save a Product model you just pass an external URL to save like so:

That’s it. Are there redundant parts in this code? Quite possibly. But after spending the better part of a day on this, I’m ready to move on and clean this up later.

Note that this doesn’t check to see if the image exists already. I’ll have to do that later, and will update code once it’s done. Right now if img.gif exists, this will create img_1.gif, ing_2.gif, and so on.