Changed the way post_save and post_delete signals are being handled.

One handler is created per model instead of per bound image spec.
This cuts down on the number of handlers created, and also offloads the
policing of the handlers in memory to the signal framework. Since they are no
longer being created per spec, the handlers can be weakly referenced.
This commit is contained in:
Eric Eldredge 2011-09-21 10:37:50 -04:00
parent b1c5432310
commit fe2fb844af

View file

@ -64,15 +64,13 @@ class ImageSpec(object):
def contribute_to_class(self, cls, name):
setattr(cls, name, _ImageSpecDescriptor(self, name))
# Connect to the signals only once for this class's attribute.
uid = '%s.%s_%s' % (cls.__module__, cls.__name__, name)
post_save.connect(_create_post_save_handler(name),
# Connect to the signals only once for this class.
uid = '%s.%s' % (cls.__module__, cls.__name__)
post_save.connect(_post_save_handler,
sender=cls,
weak=False,
dispatch_uid='%s_save' % uid)
post_delete.connect(_create_post_delete_handler(name, uid),
post_delete.connect(_post_delete_handler,
sender=cls,
weak=False,
dispatch_uid='%s.delete' % uid)
@ -240,21 +238,21 @@ class _ImageSpecDescriptor(object):
return BoundImageSpec(instance, self._spec, self._property_name)
def _create_post_save_handler(accessor_name):
def handler(sender, instance=None, created=False, raw=False, **kwargs):
if raw:
return
accessor = getattr(instance, accessor_name)
spec = accessor.spec
imgfield = spec._get_imgfield(instance)
def _post_save_handler(sender, instance=None, created=False, raw=False, **kwargs):
if raw:
return
bound_specs = _get_bound_specs(instance)
for bound_spec in bound_specs:
name = bound_spec.property_name
imgfield = bound_spec._get_imgfield(instance)
newfile = imgfield.storage.open(str(imgfield))
img = Image.open(newfile)
img, format = spec.process(img, instance)
img, format = bound_spec.process(img, instance)
if format != 'JPEG':
imgfile = img_to_fobj(img, format)
else:
imgfile = img_to_fobj(img, format,
quality=int(spec.quality),
quality=int(bound_spec.quality),
optimize=True)
content = ContentFile(imgfile.read())
newfile.close()
@ -262,17 +260,24 @@ def _create_post_save_handler(accessor_name):
imgfield.storage.delete(name)
imgfield.storage.save(name, content)
if not created:
accessor._delete()
accessor._create()
return handler
bound_spec._delete()
bound_spec._create()
def _create_post_delete_handler(accessor_name, uid):
def handler(sender, instance=None, **kwargs):
assert instance._get_pk_val() is not None, "%s object can't be deleted because its %s attribute is set to None." % (instance._meta.object_name, instance._meta.pk.attname)
accessor = getattr(instance, accessor_name)
accessor._delete()
post_save.disconnect(dispatch_uid='%s_save' % uid)
post_delete.disconnect(dispatch_uid='%s.delete' % uid)
def _post_delete_handler(sender, instance=None, **kwargs):
assert instance._get_pk_val() is not None, "%s object can't be deleted because its %s attribute is set to None." % (instance._meta.object_name, instance._meta.pk.attname)
bound_specs = _get_bound_specs(instance)
for bound_spec in bound_specs:
bound_spec._delete()
return handler
def _get_bound_specs(instance):
bound_specs = []
for key in dir(instance):
try:
value = getattr(instance, key)
except AttributeError:
continue
if isinstance(value, BoundImageSpec):
bound_specs.append(value)
return bound_specs