Merge remote-tracking branch 'origin/pr/346' into 345

Conflicts:
	AUTHORS
	docs/guide/signals.rst
This commit is contained in:
Ross Lawley 2013-06-04 09:35:26 +00:00
commit ef4b32aca7
3 changed files with 111 additions and 20 deletions

View File

@ -77,7 +77,7 @@ that much better:
* Adam Parrish * Adam Parrish
* jpfarias * jpfarias
* jonrscott * jonrscott
* Alice Zoë Bevan-McGregor * Alice Zoë Bevan-McGregor (https://github.com/amcgregor/)
* Stephen Young * Stephen Young
* tkloc * tkloc
* aid * aid

View File

@ -403,7 +403,7 @@ either a single field name, or a list or tuple of field names::
Skipping Document validation on save Skipping Document validation on save
------------------------------------ ------------------------------------
You can also skip the whole document validation process by setting You can also skip the whole document validation process by setting
``validate=False`` when caling the :meth:`~mongoengine.document.Document.save` ``validate=False`` when calling the :meth:`~mongoengine.document.Document.save`
method:: method::
class Recipient(Document): class Recipient(Document):

View File

@ -1,5 +1,6 @@
.. _signals: .. _signals:
=======
Signals Signals
======= =======
@ -7,33 +8,95 @@ Signals
.. note:: .. note::
Signal support is provided by the excellent `blinker`_ library and Signal support is provided by the excellent `blinker`_ library. If you wish
will gracefully fall back if it is not available. to enable signal support this library must be installed, though it is not
required for MongoEngine to function.
Overview
--------
The following document signals exist in MongoEngine and are pretty self-explanatory: 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.
* `mongoengine.signals.pre_init` Available signals include:
* `mongoengine.signals.post_init`
* `mongoengine.signals.pre_save_validation`
* `mongoengine.signals.pre_save`
* `mongoengine.signals.post_save`
* `mongoengine.signals.pre_delete`
* `mongoengine.signals.post_delete`
* `mongoengine.signals.pre_bulk_insert`
* `mongoengine.signals.post_bulk_insert`
Example usage:: `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.Document.save` prior to performing
any actions.
`pre_save_post_validation`
Called within :meth:`~mongoengine.document.Document.save` after validation
has taken place but before saving.
`post_save`
Called within :meth:`~mongoengine.document.Document.save` after all actions
(validation, insert/update, cascades, 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.Document.delete` prior to
attempting the delete operation.
`post_delete`
Called within :meth:`~mongoengine.document.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 *
from mongoengine import signals 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): class Author(Document):
name = StringField() name = StringField()
def __unicode__(self):
return self.name
@classmethod @classmethod
def pre_save(cls, sender, document, **kwargs): def pre_save(cls, sender, document, **kwargs):
logging.debug("Pre Save: %s" % document.name) logging.debug("Pre Save: %s" % document.name)
@ -50,12 +113,40 @@ Example usage::
signals.pre_save.connect(Author.pre_save, sender=Author) signals.pre_save.connect(Author.pre_save, sender=Author)
signals.post_save.connect(Author.post_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::
ReferenceFields and signals 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()
ReferenceFields and Signals
--------------------------- ---------------------------
Currently `reverse_delete_rules` do not trigger signals on the other part of Currently `reverse_delete_rules` do not trigger signals on the other part of
the relationship. If this is required you must manually handled the the relationship. If this is required you must manually handle the
reverse deletion. reverse deletion.
.. _blinker: http://pypi.python.org/pypi/blinker .. _blinker: http://pypi.python.org/pypi/blinker