import requests from io import BytesIO from django.conf import settings from django.core.files.uploadedfile import InMemoryUploadedFile from django.db import models, transaction from django.dispatch import receiver from django_images.models import Image as BaseImage, Thumbnail from taggit.managers import TaggableManager from users.models import User class ImageManager(models.Manager): _default_ua = { 'User-Agent': 'Mozilla/5.0 (Windows NT 5.1) ' 'AppleWebKit/537.36 (KHTML, like Gecko) ' 'Chrome/48.0.2564.82 Safari/537.36', } # FIXME: Move this into an asynchronous task def create_for_url(self, url, referer=None): file_name = url.split("/")[-1].split('#')[0].split('?')[0] buf = BytesIO() headers = dict(self._default_ua) if referer is not None: headers["Referer"] = referer response = requests.get(url, headers=headers) buf.write(response.content) obj = InMemoryUploadedFile(buf, 'image', file_name, None, buf.tell(), None) # create the image and its thumbnails in one transaction, removing # a chance of getting Database into a inconsistent state when we # try to create thumbnails one by one later image = self.create(image=obj) for size in settings.IMAGE_SIZES.keys(): Thumbnail.objects.get_or_create_at_size(image.pk, size) return image class Image(BaseImage): objects = ImageManager() class Sizes: standard = "standard" thumbnail = "thumbnail" square = "square" class Meta: proxy = True @property def standard(self): return Thumbnail.objects.get( original=self, size=self.Sizes.standard ) @property def thumbnail(self): return Thumbnail.objects.get( original=self, size=self.Sizes.thumbnail ) @property def square(self): return Thumbnail.objects.get( original=self, size=self.Sizes.square ) class Pin(models.Model): submitter = models.ForeignKey(User) url = models.URLField(null=True, blank=True) origin = models.URLField(null=True, blank=True) referer = models.URLField(null=True, blank=True) description = models.TextField(blank=True, null=True) image = models.ForeignKey(Image, related_name='pin') published = models.DateTimeField(auto_now_add=True) tags = TaggableManager() def tag_list(self): return self.tags.all() def __unicode__(self): return '%s - %s' % (self.submitter, self.published) @receiver(models.signals.post_delete, sender=Pin) def delete_pin_images(sender, instance, **kwargs): try: instance.image.delete() except Image.DoesNotExist: pass