1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147 | import os.path
from UserDict import DictMixin
from django.db.models.fields.files import ImageField, ImageFieldFile
from django.utils.safestring import mark_safe
from django.utils.functional import curry
from django.utils.html import escape
from django.conf import settings
from sorl.thumbnail.main import DjangoThumbnail
from sorl.thumbnail.utils import delete_thumbnails
REQUIRED_ARGS = ('size',)
ALL_ARGS = {
'size': 'requested_size',
'options': 'opts',
'quality': 'quality',
'basedir': 'basedir',
'subdir': 'subdir',
'prefix': 'prefix',
'extension': 'extension',
}
TAG_HTML = '<img src="%(src)s" width="%(width)s" height="%(height)s" alt="" />'
class ThumbsDict(object, DictMixin):
def __init__(self, descriptor):
super(ThumbsDict, self).__init__()
self.descriptor = descriptor
def keys(self):
return self.descriptor.field.extra_thumbnails.keys()
class LazyThumbs(ThumbsDict):
def __init__(self, *args, **kwargs):
super(LazyThumbs, self).__init__(*args, **kwargs)
self.cached = {}
def __getitem__(self, key):
thumb = self.cached.get(key)
if not thumb:
args = self.descriptor.field.extra_thumbnails[key]
thumb = self.descriptor._build_thumbnail(args)
self.cached[key] = thumb
return thumb
def keys(self):
return self.descriptor.field.extra_thumbnails.keys()
class ThumbTags(ThumbsDict):
def __getitem__(self, key):
thumb = self.descriptor.extra_thumbnails[key]
return self.descriptor._build_thumbnail_tag(thumb)
class ImageWithThumbnailsFieldFile(ImageFieldFile):
def _build_thumbnail(self, args):
# Build kwargs
kwargs = {}
for k, v in args.items():
kwargs[ALL_ARGS[k]] = v
# Return thumbnail
relative_source_path = getattr(self.instance, self.field.name).name
return DjangoThumbnail(relative_source_path, **kwargs)
def _build_thumbnail_tag(self, thumb):
opts = dict(src=escape(thumb), width=thumb.width(),
height=thumb.height())
return mark_safe(self.field.thumbnail_tag % opts)
def _get_thumbnail(self):
return self._build_thumbnail(self.field.thumbnail)
thumbnail = property(_get_thumbnail)
def _get_extra_thumbnails(self):
if self.field.extra_thumbnails is None:
return None
if not hasattr(self, '_extra_thumbnails'):
self._extra_thumbnails = LazyThumbs(self)
return self._extra_thumbnails
extra_thumbnails = property(_get_extra_thumbnails)
def _get_thumbnail_tag(self):
return self._build_thumbnail_tag(self.thumbnail)
thumbnail_tag = property(_get_thumbnail_tag)
def _get_extra_thumbnails_tag(self):
if self.field.extra_thumbnails is None:
return None
return ThumbTags(self)
extra_thumbnails_tag = property(_get_extra_thumbnails_tag)
# TODO: Should thumbnails be generated when image is saved?
# def save(self, name, content, save=True):
# # Generate the thumbnails when the image is saved.
# super(ImageWithThumbnailsFieldFile, self).save(name, content, save)
def delete(self, save=True):
# Delete any thumbnails too (and not just ones defined here in case
# the {% thumbnail %} tag was used or the thumbnail sizes changed).
relative_source_path = getattr(self.instance, self.field.name).name
delete_thumbnails(relative_source_path)
super(ImageWithThumbnailsFieldFile, self).delete(save)
class ImageWithThumbnailsField(ImageField):
"""
photo = ImageWithThumbnailsField(
upload_to='uploads',
thumbnail={'size': (80, 80), 'options': ('crop', 'upscale'),
'extension': 'png'},
extra_thumbnails={
'admin': {'size': (70, 50), 'options': ('sharpen',)},
},
)
"""
attr_class = ImageWithThumbnailsFieldFile
def __init__(self, *args, **kwargs):
# The new arguments for this field aren't explicitly defined so that
# users can still use normal ImageField positional arguments.
thumbnail=kwargs.pop('thumbnail', None)
extra_thumbnails=kwargs.pop('extra_thumbnails', None)
thumbnail_tag=kwargs.pop('thumbnail_tag', TAG_HTML)
super(ImageWithThumbnailsField, self).__init__(*args, **kwargs)
if thumbnail:
_verify_thumbnail_attrs(thumbnail)
if extra_thumbnails:
for extra, attrs in extra_thumbnails.items():
name = "%r of 'extra_thumbnails'"
_verify_thumbnail_attrs(attrs, name)
self.thumbnail = thumbnail
self.extra_thumbnails = extra_thumbnails
self.thumbnail_tag = thumbnail_tag
def _verify_thumbnail_attrs(attrs, name="'thumbnail'"):
for arg in REQUIRED_ARGS:
if arg not in attrs:
raise TypeError('Required attr %r missing in %s arg' % (arg, name))
for attr in attrs:
if attr not in ALL_ARGS:
raise TypeError('Invalid attr %r found in %s arg' % (arg, name))
|