2.8. Signals
Added in version 0.5.
2.8.1. 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
DocumentorEmbeddedDocumentinstance, 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 thevalueskeyword argument and may modify this dictionary prior to returning. - post_init
- Called after all processing of a
new
DocumentorEmbeddedDocumentinstance has been completed. - pre_save
- Called within
save()prior to performing any actions. - pre_save_post_validation
- Called within
save()after validation has taken place but before saving. - post_save
- Called within
save()after most actions (validation, insert/update, and cascades, but not clearing dirty flags) have completed successfully. Passed the additional boolean keyword argumentcreatedto indicate if the save was an insert or an update. - pre_delete
- Called within
delete()prior to attempting the delete operation. - post_delete
- Called within
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
documentargument is replaced by adocumentsargument representing the list of documents being inserted. - post_bulk_insert
- Called after a successful bulk
insert operation. As per
pre_bulk_insert, thedocumentargument is omitted and replaced with adocumentsargument. An additional boolean argument,loaded, identifies the contents of documents as eitherDocumentinstances whenTrueor simply a list of primary key values for the inserted records ifFalse.
2.8.2. 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 Document or
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)
EmbeddedDocument only supports pre/post_init signals.
pre/post_save, etc should be attached to Document's class only.
Attaching pre_save to an EmbeddedDocument is ignored silently.
Finally, you can also use this small decorator to quickly create a number of signals and
attach them to your Document or 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()