Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 
 
 
 

130 rader
4.2 KiB

  1. import hashlib
  2. import os.path
  3. from django.db import models
  4. from django.core.files.uploadedfile import InMemoryUploadedFile
  5. from django.core.urlresolvers import reverse
  6. from django.dispatch import receiver
  7. try:
  8. from importlib import import_module
  9. except ImportError:
  10. from django.utils.importlib import import_module
  11. from . import utils
  12. from .settings import IMAGE_SIZES, IMAGE_PATH, IMAGE_AUTO_DELETE
  13. def hashed_upload_to(instance, filename, **kwargs):
  14. image_type = 'original' if isinstance(instance, Image) else 'thumbnail'
  15. prefix = 'image/%s/by-md5/' % (image_type,)
  16. hasher = hashlib.md5()
  17. for chunk in instance.image.chunks():
  18. hasher.update(chunk)
  19. hash_ = hasher.hexdigest()
  20. base, ext = os.path.splitext(filename)
  21. return '%(prefix)s%(first)s/%(second)s/%(hash)s/%(base)s%(ext)s' % {
  22. 'prefix': prefix,
  23. 'first': hash_[0],
  24. 'second': hash_[1],
  25. 'hash': hash_,
  26. 'base': base,
  27. 'ext': ext,
  28. }
  29. if IMAGE_PATH is None:
  30. upload_to = hashed_upload_to
  31. else:
  32. if callable(IMAGE_PATH):
  33. upload_to = IMAGE_PATH
  34. else:
  35. parts = IMAGE_PATH.split('.')
  36. module_name = '.'.join(parts[:-1])
  37. module = import_module(module_name)
  38. upload_to = getattr(module, parts[-1])
  39. class Image(models.Model):
  40. image = models.ImageField(upload_to=upload_to,
  41. height_field='height', width_field='width',
  42. max_length=255)
  43. height = models.PositiveIntegerField(default=0, editable=False)
  44. width = models.PositiveIntegerField(default=0, editable=False)
  45. def get_by_size(self, size):
  46. return self.thumbnail_set.get(size=size)
  47. def get_absolute_url(self, size=None):
  48. if not size:
  49. return self.image.url
  50. try:
  51. return self.get_by_size(size).image.url
  52. except Thumbnail.DoesNotExist:
  53. return reverse('image-thumbnail', args=(self.id, size))
  54. class ThumbnailManager(models.Manager):
  55. def get_or_create_at_sizes(self, image, sizes):
  56. sizes_to_create = list(sizes)
  57. sized = {}
  58. for size in sizes:
  59. if size not in IMAGE_SIZES:
  60. raise ValueError("Received unknown size: %s" % size)
  61. try:
  62. sized[size] = image.get_by_size(size)
  63. except Thumbnail.DoesNotExist:
  64. pass
  65. else:
  66. sizes_to_create.remove(size)
  67. if sizes_to_create:
  68. bufs = [
  69. utils.write_image_in_memory(img)
  70. for img in utils.scale_and_crop_iter(
  71. image.image,
  72. [IMAGE_SIZES[size] for size in sizes_to_create])
  73. ]
  74. for size, buf in zip(sizes_to_create, bufs):
  75. # and save to storage
  76. original_dir, original_file = os.path.split(image.image.name)
  77. thumb_file = InMemoryUploadedFile(buf, "image", original_file,
  78. None, buf.tell(), None)
  79. sized[size], created = image.thumbnail_set.get_or_create(
  80. size=size, defaults={'image': thumb_file})
  81. # Make sure this is in the correct order
  82. return [sized[size] for size in sizes]
  83. class Thumbnail(models.Model):
  84. original = models.ForeignKey(Image)
  85. image = models.ImageField(upload_to=upload_to,
  86. height_field='height', width_field='width',
  87. max_length=255)
  88. size = models.CharField(max_length=100)
  89. height = models.PositiveIntegerField(default=0, editable=False)
  90. width = models.PositiveIntegerField(default=0, editable=False)
  91. objects = ThumbnailManager()
  92. class Meta:
  93. unique_together = ('original', 'size')
  94. def get_absolute_url(self):
  95. return self.image.url
  96. @receiver(models.signals.post_save)
  97. def original_changed(sender, instance, created, **kwargs):
  98. if isinstance(instance, Image):
  99. instance.thumbnail_set.all().delete()
  100. @receiver(models.signals.post_delete)
  101. def delete_image_files(sender, instance, **kwargs):
  102. if isinstance(instance, (Image, Thumbnail)) and IMAGE_AUTO_DELETE:
  103. if instance.image.storage.exists(instance.image.name):
  104. instance.image.delete(save=False)