146 lines
4.8 KiB
ReStructuredText
146 lines
4.8 KiB
ReStructuredText
.. _signals:
|
|
|
|
=======
|
|
Signals
|
|
=======
|
|
|
|
.. versionadded:: 0.5
|
|
|
|
.. note::
|
|
|
|
Signal support is provided by the excellent `blinker`_ library. If you wish
|
|
to enable signal support this library must be installed, though it is not
|
|
required for MongoEngine to function.
|
|
|
|
Overview
|
|
--------
|
|
|
|
Signals are found within the `mongoengine.signals` module. Unless
|
|
specified signals receive no additional arguments beyond the `sender` class and
|
|
`document` instance. Post-signals are only called if there were no exceptions
|
|
raised during the processing of their related function.
|
|
|
|
Available signals include:
|
|
|
|
`pre_init`
|
|
Called during the creation of a new :class:`~mongoengine.Document` or
|
|
:class:`~mongoengine.EmbeddedDocument` instance, after the constructor
|
|
arguments have been collected but before any additional processing has been
|
|
done to them. (I.e. assignment of default values.) Handlers for this signal
|
|
are passed the dictionary of arguments using the `values` keyword argument
|
|
and may modify this dictionary prior to returning.
|
|
|
|
`post_init`
|
|
Called after all processing of a new :class:`~mongoengine.Document` or
|
|
:class:`~mongoengine.EmbeddedDocument` instance has been completed.
|
|
|
|
`pre_save`
|
|
Called within :meth:`~mongoengine.Document.save` prior to performing
|
|
any actions.
|
|
|
|
`pre_save_post_validation`
|
|
Called within :meth:`~mongoengine.Document.save` after validation
|
|
has taken place but before saving.
|
|
|
|
`post_save`
|
|
Called within :meth:`~mongoengine.Document.save` after most actions
|
|
(validation, insert/update, and cascades, but not clearing dirty flags) have
|
|
completed successfully. Passed the additional boolean keyword argument
|
|
`created` to indicate if the save was an insert or an update.
|
|
|
|
`pre_delete`
|
|
Called within :meth:`~mongoengine.Document.delete` prior to
|
|
attempting the delete operation.
|
|
|
|
`post_delete`
|
|
Called within :meth:`~mongoengine.Document.delete` upon successful
|
|
deletion of the record.
|
|
|
|
`pre_bulk_insert`
|
|
Called after validation of the documents to insert, but prior to any data
|
|
being written. In this case, the `document` argument is replaced by a
|
|
`documents` argument representing the list of documents being inserted.
|
|
|
|
`post_bulk_insert`
|
|
Called after a successful bulk insert operation. As per `pre_bulk_insert`,
|
|
the `document` argument is omitted and replaced with a `documents` argument.
|
|
An additional boolean argument, `loaded`, identifies the contents of
|
|
`documents` as either :class:`~mongoengine.Document` instances when `True` or
|
|
simply a list of primary key values for the inserted records if `False`.
|
|
|
|
Attaching Events
|
|
----------------
|
|
|
|
After writing a handler function like the following::
|
|
|
|
import logging
|
|
from datetime import datetime
|
|
|
|
from mongoengine import *
|
|
from mongoengine import signals
|
|
|
|
def update_modified(sender, document):
|
|
document.modified = datetime.utcnow()
|
|
|
|
You attach the event handler to your :class:`~mongoengine.Document` or
|
|
:class:`~mongoengine.EmbeddedDocument` subclass::
|
|
|
|
class Record(Document):
|
|
modified = DateTimeField()
|
|
|
|
signals.pre_save.connect(update_modified)
|
|
|
|
While this is not the most elaborate document model, it does demonstrate the
|
|
concepts involved. As a more complete demonstration you can also define your
|
|
handlers within your subclass::
|
|
|
|
class Author(Document):
|
|
name = StringField()
|
|
|
|
@classmethod
|
|
def pre_save(cls, sender, document, **kwargs):
|
|
logging.debug("Pre Save: %s" % document.name)
|
|
|
|
@classmethod
|
|
def post_save(cls, sender, document, **kwargs):
|
|
logging.debug("Post Save: %s" % document.name)
|
|
if 'created' in kwargs:
|
|
if kwargs['created']:
|
|
logging.debug("Created")
|
|
else:
|
|
logging.debug("Updated")
|
|
|
|
signals.pre_save.connect(Author.pre_save, sender=Author)
|
|
signals.post_save.connect(Author.post_save, sender=Author)
|
|
|
|
Finally, you can also use this small decorator to quickly create a number of
|
|
signals and attach them to your :class:`~mongoengine.Document` or
|
|
:class:`~mongoengine.EmbeddedDocument` subclasses as class decorators::
|
|
|
|
def handler(event):
|
|
"""Signal decorator to allow use of callback functions as class decorators."""
|
|
|
|
def decorator(fn):
|
|
def apply(cls):
|
|
event.connect(fn, sender=cls)
|
|
return cls
|
|
|
|
fn.apply = apply
|
|
return fn
|
|
|
|
return decorator
|
|
|
|
Using the first example of updating a modification time the code is now much
|
|
cleaner looking while still allowing manual execution of the callback::
|
|
|
|
@handler(signals.pre_save)
|
|
def update_modified(sender, document):
|
|
document.modified = datetime.utcnow()
|
|
|
|
@update_modified.apply
|
|
class Record(Document):
|
|
modified = DateTimeField()
|
|
|
|
|
|
.. _blinker: http://pypi.python.org/pypi/blinker
|