Signal support
Models with hooks for signals (a-la django) are provided in playhouse.signals
. To use the signals, you will need all of your project’s models to be a subclass of playhouse.signals.Model
, which overrides the necessary methods to provide support for the various signals.
from playhouse.signals import Model, post_save
class MyModel(Model):
data = IntegerField()
@post_save(sender=MyModel)
def on_save_handler(model_class, instance, created):
put_data_in_cache(instance.data)
Warning
For what I hope are obvious reasons, Peewee signals do not work when you use the Model.insert()
, Model.update()
, or Model.delete()
methods. These methods generate queries that execute beyond the scope of the ORM, and the ORM does not know about which model instances might or might not be affected when the query executes.
Signals work by hooking into the higher-level peewee APIs like Model.save()
and Model.delete_instance()
, where the affected model instance is known ahead of time.
The following signals are provided:
pre_save
Called immediately before an object is saved to the database. Provides an additional keyword argument created
, indicating whether the model is being saved for the first time or updated.
post_save
Called immediately after an object is saved to the database. Provides an additional keyword argument created
, indicating whether the model is being saved for the first time or updated.
pre_delete
Called immediately before an object is deleted from the database when Model.delete_instance()
is used.
post_delete
Called immediately after an object is deleted from the database when Model.delete_instance()
is used.
pre_init
Called when a model class is first instantiated
Connecting handlers
Whenever a signal is dispatched, it will call any handlers that have been registered. This allows totally separate code to respond to events like model save and delete.
The Signal
class provides a connect()
method, which takes a callback function and two optional parameters for “sender” and “name”. If specified, the “sender” parameter should be a single model class and allows your callback to only receive signals from that one model class. The “name” parameter is used as a convenient alias in the event you wish to unregister your signal handler.
Example usage:
from playhouse.signals import *
def post_save_handler(sender, instance, created):
print('%s was just saved' % instance)
# our handler will only be called when we save instances of SomeModel
post_save.connect(post_save_handler, sender=SomeModel)
All signal handlers accept as their first two arguments sender
and instance
, where sender
is the model class and instance
is the actual model being acted upon.
If you’d like, you can also use a decorator to connect signal handlers. This is functionally equivalent to the above example:
@post_save(sender=SomeModel)
def post_save_handler(sender, instance, created):
print('%s was just saved' % instance)
Signal API
class Signal
Stores a list of receivers (callbacks) and calls them when the “send” method is invoked.
connect
(receiver[, sender=None[, name=None]])Parameters: - receiver (callable) – a callable that takes at least two parameters, a “sender”, which is the Model subclass that triggered the signal, and an “instance”, which is the actual model instance.
- sender (Model) – if specified, only instances of this model class will trigger the receiver callback.
- name (string) – a short alias
Add the receiver to the internal list of receivers, which will be called whenever the signal is sent.
from playhouse.signals import post_save
from project.handlers import cache_buster
post_save.connect(cache_buster, name='project.cache_buster')
disconnect
([receiver=None[, name=None]])Parameters: - receiver (callable) – the callback to disconnect
- name (string) – a short alias
Disconnect the given receiver (or the receiver with the given name alias) so that it no longer is called. Either the receiver or the name must be provided.
post_save.disconnect(name='project.cache_buster')
send
(instance, \args, **kwargs*)Parameters: instance – a model instance Iterates over the receivers and will call them in the order in which they were connected. If the receiver specified a sender, it will only be called if the instance is an instance of the sender.