mirror of
https://github.com/Hopiu/django-imagekit.git
synced 2026-04-19 12:41:10 +00:00
Merge branch 'source-signal-cleanup' into develop
This commit is contained in:
commit
33b8913031
9 changed files with 74 additions and 64 deletions
|
|
@ -122,7 +122,7 @@ The answer is that, when you define an ImageSpecField, ImageKit automatically
|
|||
creates and registers an object called a *source group*. Source groups are
|
||||
responsible for two things:
|
||||
|
||||
1. They dispatch signals when a source is created, changed, or deleted, and
|
||||
1. They dispatch signals when a source is saved, and
|
||||
2. They expose a generator method that enumerates source files.
|
||||
|
||||
When these objects are registered (using ``imagekit.register.source_group()``),
|
||||
|
|
@ -177,7 +177,6 @@ Running the "generateimages" management command would now cause thumbnails to be
|
|||
generated (using the "myapp:profile:avatar_thumbnail" spec) for each of the
|
||||
JPEGs in `/path/to/some/pics`.
|
||||
|
||||
Note that, since this source group doesnt send the `source_created` or
|
||||
`source_changed` signals, the corresponding cache file strategy callbacks
|
||||
would not be called for them.
|
||||
Note that, since this source group doesnt send the `source_saved` signal, the
|
||||
corresponding cache file strategy callbacks would not be called for them.
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ Cache File Strategy
|
|||
-------------------
|
||||
|
||||
Each ``ImageCacheFile`` has a cache file strategy, which abstracts away when
|
||||
image is actually generated. It can implement the following four methods:
|
||||
image is actually generated. It can implement the following three methods:
|
||||
|
||||
* ``on_content_required`` - called by ``ImageCacheFile`` when it requires the
|
||||
contents of the generated image. For example, when you call ``read()`` or
|
||||
|
|
@ -41,9 +41,7 @@ image is actually generated. It can implement the following four methods:
|
|||
* ``on_existence_required`` - called by ``ImageCacheFile`` when it requires the
|
||||
generated image to exist but may not be concerned with its contents. For
|
||||
example, when you access its ``url`` or ``path`` attribute.
|
||||
* ``on_source_created`` - called when the source of a spec is created
|
||||
* ``on_source_changed`` - called when the source of a spec is changed
|
||||
* ``on_source_deleted`` - called when the source of a spec is deleted
|
||||
* ``on_source_saved`` - called when the source of a spec is saved
|
||||
|
||||
The default strategy only defines the first two of these, as follows:
|
||||
|
||||
|
|
|
|||
|
|
@ -23,10 +23,7 @@ class Optimistic(object):
|
|||
|
||||
"""
|
||||
|
||||
def on_source_created(self, file):
|
||||
file.generate()
|
||||
|
||||
def on_source_changed(self, file):
|
||||
def on_source_saved(self, file):
|
||||
file.generate()
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
from .exceptions import AlreadyRegistered, NotRegistered
|
||||
from .signals import (content_required, existence_required, source_created,
|
||||
source_changed, source_deleted)
|
||||
from .signals import content_required, existence_required, source_saved
|
||||
from .utils import call_strategy_method
|
||||
|
||||
|
||||
|
|
@ -70,9 +69,7 @@ class SourceGroupRegistry(object):
|
|||
|
||||
"""
|
||||
_signals = {
|
||||
source_created: 'on_source_created',
|
||||
source_changed: 'on_source_changed',
|
||||
source_deleted: 'on_source_deleted',
|
||||
source_saved: 'on_source_saved',
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
|
|
|
|||
|
|
@ -6,6 +6,4 @@ content_required = Signal()
|
|||
existence_required = Signal()
|
||||
|
||||
# Source group signals
|
||||
source_created = Signal()
|
||||
source_changed = Signal()
|
||||
source_deleted = Signal()
|
||||
source_saved = Signal()
|
||||
|
|
|
|||
|
|
@ -2,20 +2,19 @@
|
|||
Source groups are the means by which image spec sources are identified. They
|
||||
have two responsibilities:
|
||||
|
||||
1. To dispatch ``source_created``, ``source_changed``, and ``source_deleted``
|
||||
signals. (These will be relayed to the corresponding specs' cache file
|
||||
strategies.)
|
||||
1. To dispatch ``source_saved`` signals. (These will be relayed to the
|
||||
corresponding specs' cache file strategies.)
|
||||
2. To provide the source files that they represent, via a generator method named
|
||||
``files()``. (This is used by the generateimages management command for
|
||||
"pre-caching" image files.)
|
||||
|
||||
"""
|
||||
|
||||
from django.db.models.signals import post_init, post_save, post_delete
|
||||
from django.db.models.signals import post_init, post_save
|
||||
from django.utils.functional import wraps
|
||||
import inspect
|
||||
from ..cachefiles import LazyImageCacheFile
|
||||
from ..signals import source_created, source_changed, source_deleted
|
||||
from ..signals import source_saved
|
||||
from ..utils import get_nonabstract_descendants
|
||||
|
||||
|
||||
|
|
@ -58,7 +57,6 @@ class ModelSignalRouter(object):
|
|||
uid = 'ik_spec_field_receivers'
|
||||
post_init.connect(self.post_init_receiver, dispatch_uid=uid)
|
||||
post_save.connect(self.post_save_receiver, dispatch_uid=uid)
|
||||
post_delete.connect(self.post_delete_receiver, dispatch_uid=uid)
|
||||
|
||||
def add(self, source_group):
|
||||
self._source_groups.append(source_group)
|
||||
|
|
@ -94,17 +92,9 @@ class ModelSignalRouter(object):
|
|||
old_hashes = instance._ik.get('source_hashes', {}).copy()
|
||||
new_hashes = self.update_source_hashes(instance)
|
||||
for attname, file in self.get_field_dict(instance).items():
|
||||
if created:
|
||||
self.dispatch_signal(source_created, file, sender, instance,
|
||||
if file and old_hashes[attname] != new_hashes[attname]:
|
||||
self.dispatch_signal(source_saved, file, sender, instance,
|
||||
attname)
|
||||
elif old_hashes[attname] != new_hashes[attname]:
|
||||
self.dispatch_signal(source_changed, file, sender, instance,
|
||||
attname)
|
||||
|
||||
@ik_model_receiver
|
||||
def post_delete_receiver(self, sender, instance=None, **kwargs):
|
||||
for attname, file in self.get_field_dict(instance).items():
|
||||
self.dispatch_signal(source_deleted, file, sender, instance, attname)
|
||||
|
||||
@ik_model_receiver
|
||||
def post_init_receiver(self, sender, instance=None, **kwargs):
|
||||
|
|
|
|||
|
|
@ -31,8 +31,7 @@ class CountingCacheFileStrategy(object):
|
|||
def __init__(self):
|
||||
self.on_existence_required_count = 0
|
||||
self.on_content_required_count = 0
|
||||
self.on_source_changed_count = 0
|
||||
self.on_source_created_count = 0
|
||||
self.on_source_saved_count = 0
|
||||
|
||||
def on_existence_required(self, file):
|
||||
self.on_existence_required_count += 1
|
||||
|
|
@ -40,11 +39,8 @@ class CountingCacheFileStrategy(object):
|
|||
def on_content_required(self, file):
|
||||
self.on_content_required_count += 1
|
||||
|
||||
def on_source_changed(self, file):
|
||||
self.on_source_changed_count += 1
|
||||
|
||||
def on_source_created(self, file):
|
||||
self.on_source_created_count += 1
|
||||
def on_source_saved(self, file):
|
||||
self.on_source_saved_count += 1
|
||||
|
||||
|
||||
class AbstractImageModel(models.Model):
|
||||
|
|
|
|||
|
|
@ -1,27 +1,7 @@
|
|||
from django.core.files import File
|
||||
from imagekit.signals import source_created
|
||||
from imagekit.specs.sourcegroups import ImageFieldSourceGroup
|
||||
from imagekit.utils import get_nonabstract_descendants
|
||||
from nose.tools import eq_
|
||||
from . models import (AbstractImageModel, ConcreteImageModel,
|
||||
ConcreteImageModelSubclass)
|
||||
from .utils import get_image_file
|
||||
|
||||
|
||||
def test_source_created_signal():
|
||||
source_group = ImageFieldSourceGroup(AbstractImageModel, 'original_image')
|
||||
count = [0]
|
||||
|
||||
def receiver(sender, *args, **kwargs):
|
||||
if sender is source_group:
|
||||
count[0] += 1
|
||||
|
||||
source_created.connect(receiver, dispatch_uid='test_source_created')
|
||||
instance = ConcreteImageModel()
|
||||
img = File(get_image_file())
|
||||
instance.original_image.save('test_source_created_signal.jpg', img)
|
||||
|
||||
eq_(count[0], 1)
|
||||
ConcreteImageModelSubclass)
|
||||
|
||||
|
||||
def test_nonabstract_descendants_generator():
|
||||
|
|
|
|||
55
tests/test_sourcegroups.py
Normal file
55
tests/test_sourcegroups.py
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
from django.core.files import File
|
||||
from imagekit.signals import source_saved
|
||||
from imagekit.specs.sourcegroups import ImageFieldSourceGroup
|
||||
from nose.tools import eq_
|
||||
from . models import AbstractImageModel, ImageModel, ConcreteImageModel
|
||||
from .utils import get_image_file
|
||||
|
||||
|
||||
def make_counting_receiver(source_group):
|
||||
def receiver(sender, *args, **kwargs):
|
||||
if sender is source_group:
|
||||
receiver.count += 1
|
||||
receiver.count = 0
|
||||
return receiver
|
||||
|
||||
|
||||
def test_source_saved_signal():
|
||||
"""
|
||||
Creating a new instance with an image causes the source_saved signal to be
|
||||
dispatched.
|
||||
|
||||
"""
|
||||
source_group = ImageFieldSourceGroup(ImageModel, 'image')
|
||||
receiver = make_counting_receiver(source_group)
|
||||
source_saved.connect(receiver)
|
||||
ImageModel.objects.create(image=File(get_image_file()))
|
||||
eq_(receiver.count, 1)
|
||||
|
||||
|
||||
def test_no_source_saved_signal():
|
||||
"""
|
||||
Creating a new instance without an image shouldn't cause the source_saved
|
||||
signal to be dispatched.
|
||||
|
||||
https://github.com/jdriscoll/django-imagekit/issues/214
|
||||
|
||||
"""
|
||||
source_group = ImageFieldSourceGroup(ImageModel, 'image')
|
||||
receiver = make_counting_receiver(source_group)
|
||||
source_saved.connect(receiver)
|
||||
ImageModel.objects.create()
|
||||
eq_(receiver.count, 0)
|
||||
|
||||
|
||||
def test_abstract_model_signals():
|
||||
"""
|
||||
Source groups created for abstract models must cause signals to be
|
||||
dispatched on their concrete subclasses.
|
||||
|
||||
"""
|
||||
source_group = ImageFieldSourceGroup(AbstractImageModel, 'original_image')
|
||||
receiver = make_counting_receiver(source_group)
|
||||
source_saved.connect(receiver)
|
||||
ConcreteImageModel.objects.create(original_image=File(get_image_file()))
|
||||
eq_(receiver.count, 1)
|
||||
Loading…
Reference in a new issue