#AUTOMATIC POSTER DOWNLOADING: original source: http://ishcray.com/downloading-and-saving-image-to-imagefield-in-django

import imghdr # Used to validate images

#we will use pillow's copy function rather than the copy module's copy.copy()

#IMPORTANT: install Pillow instead of PIL. import statement is the same (see Pillow docs)

from PIL import Image #Holds downloaded image and verifies it

#imports changed for python3

import urllib . request # Used to download images (python 2 version: import urllib2)

import urllib . parse # Cleans up image urls (python 2 version: import urlparse)

import io # Used to imitate reading from byte file (python 2 version: import cStringIO)

from django. core . files . base import ContentFile #used to save file. Not included in original guide

def download_image ( url ) :

"""Downloads an image and makes sure it's verified.

Returns a PIL (Pillow) Image if the image is valid, otherwise raises an exception.

"""

headers = {

'User-Agent' : 'Mozilla/5.0 (Windows NT 5.1; rv:31.0) Gecko/20100101 Firefox/31.0' } # More likely to get a response if server thinks you're a browser

r = urllib . request . Request ( url , headers = headers )

request = urllib . request . urlopen ( r , timeout = 10 )

# StringIO (io.BytesIO) imitates a file, needed for verification step

image_data = io. BytesIO ( request. read ( ) )

# Creates an instance of PIL (Pillow) Image class - PIL (Pillow) does the verification of file

img = Image. open ( image_data )

# Verify the copied image, not original - verification requires you to open the image again after verification, but since we

# don't have the file saved yet we won't be able to. This is because once we read() urllib2.urlopen we can't access the

# response again without remaking the request (i.e. downloading the image again). Rather than do that, we duplicate the PIL Image in memory.

img_copy = img. copy ( ) #uses Pillow's copy instead of the copy.copy()

if valid_img ( img_copy ) :

return img

else :

# Maybe this is not the best error handling...you might want to just provide a path to a generic image instead

raise Exception (

'An invalid image was detected when attempting to save a Product!' )

def valid_img ( img ) :

"""Verifies that an instance of a PIL Image Class is actually an image and returns either True or False. Note: Copying img returns an instance of the Pillow/PIL Image class, regardless of whether you use copy.copy or Image.copy. So all i'm doing here is checking with pillow's Image.verify() """

try :

img. verify ( )

return True

except :

return False

else :

return False

class Movie ( models. Model ) :

title = models. CharField ( max_length = 125 )

release_year = models. IntegerField ( )

overview = models. CharField ( max_length = 325 )

poster_url = models. URLField ( max_length = 200 )

poster = models. ImageField ( upload_to = poster_directory_path , null = True , blank = True )

def save ( self , *args , **kwargs ) :

'''I take the url from a field in my Movie model, but feel free to add it back as an argument for the save function'''

url = self . poster_url

if self . poster != '' and url != '' : # Don't do anything if we don't get passed anything!

image = download_image ( url ) # See function definition below

try :

filename = urllib . parse . urlparse ( url ) . path . split ( '/' ) [ - 1 ]

self . poster = filename

tempfile = image

# Will make a file-like object in memory that you can then save

tempfile_io = io. BytesIO ( )

tempfile . save ( tempfile_io , format = image. format )

# Set save=False otherwise you will have a looping save method

self . poster . save ( filename , ContentFile (

tempfile_io. getvalue ( ) ) , save = False )

except Exception as e:

print ( "Error trying to save model: saving image failed: " + str ( e ) )

pass

# We've gotten the image into the ImageField above...now we actually need to save it. We've redefined the save

# method for Product (Movie) , so super *should* get the parent of class Product (Movie), models.Model and then run IT'S save

# method, which will save the Product (Movie) like normal

super ( Movie , self ) . save ( *args , **kwargs )

def __str__ ( self ) :