Question

I have got an image url and I want to set a ProcessedImageField attribute from it during object saving. So far I have got this:

 class Video(Media):
      url = models.URLField('url', max_length=256, default='')
      embed_url = models.URLField('embed url', max_length=256, default='')
      thumbnail = ProcessedImageField(upload_to='uploads',
                                  processors=[ResizeToFit(width=1024, height=1024, upscale=False)],
                                  format='JPEG',
                                  options={'quality': 75})


    def save(self, *args, **kwargs):
        from django.core.files.temp import NamedTemporaryFile
        import shutil
        import requests
        import re

        params = {
            'url': self.url,
            'autoplay': 1,
            'format': 'json',
        }

        try:
            data = requests.get('http://www.youtube.com/oembed', params=params).json()          
            embed_url = re.search('src=[\'"]([^\'"]*)[\'"]', data['html']).group(1)                
            thumbnail_url = data['thumbnail_url']
        except:
            pass

        response = requests.get(thumbnail_url, stream=True)
        img_temp = NamedTemporaryFile(delete=True)
        shutil.copyfileobj(response.raw, img_temp)

        # now image data are in img_temp, how to pass that to ProcessedImageField?

        super(Video, self).save(*args, **kwargs)
Was it helpful?

Solution

You should be able to save directly to that property at that point.

self.thumbnail.save("filename.ext", img_temp)

OTHER TIPS

This is the resulting code (without error handling) of mine. In the end, I did in in a simpler manner by avoiding a temporary file and using ContentFile instead.

class Video(Media):
    url = models.URLField('url', max_length=256, default='')
    embed_url = models.URLField('embed url', max_length=256, default='')
    author = models.CharField('author', max_length=64, default='', blank=True)
    thumbnail = ProcessedImageField(upload_to='uploads',
                                processors=[ResizeToFit(width=1024, height=1024, upscale=False)],
                                format='JPEG',
                                options={'quality': 75})

    def save(self, *args, **kwargs):
        from django.core.files.base import ContentFile
        import requests
        import re

        params = {
            'url': self.url,
            'format': 'json',
        }

        data = requests.get('http://www.youtube.com/oembed', params=params).json()
        embed_url = re.search('src=[\'"]([^\'"]*)[\'"]', data['html']).group(1)
        thumbnail_url = data['thumbnail_url']
        author = data['author_name']
        title = data['title']

        image_data = requests.get(thumbnail_url, stream=True).raw.data
        self.thumbnail.save(title, ContentFile(image_data), save=False)
        self.embed_url = embed_url
        self.author = author
        self.title = title

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

Ok, i've ended with this code for Python 3 :) it has built-in retries with timeouts between them and support for downloading large files

def save_image_from_url(self, image_url):
    s = requests.Session()
    retries = Retry(total=5,
                    backoff_factor=0.1,
                    status_forcelist=[500, 502, 503, 504])
    s.mount('https://', HTTPAdapter(max_retries=retries))
    response = s.get(image_url, stream=True, timeout=9)
    # here just use whatever name you want, I've just retrieve the path from my custom field
    folder_name = Artist.image.field.upload_to.sub_path
    random_name = uuid.uuid4().hex + ".png"
    # creating folder if it doen't exist
    try:
        os.makedirs(os.path.join(settings.MEDIA_ROOT, folder_name))
    except OSError as e:
        if e.errno != errno.EEXIST:
            raise
    # loading image to tmp location and saving it, it's for large files because we can't handle them in memory
    tmp = tempfile.NamedTemporaryFile(delete=True)
    try:
        tmp.write(response.raw.read())
        with open(tmp.name, 'rb') as f:
            self.image.save(random_name, f)
    finally:
        tmp.close()

Where self.image is ProcessedImageField

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top