class documentation

class AttributeEvents(event.Events):

View In Hierarchy

Define events for object attributes.

These are typically defined on the class-bound descriptor for the target class.

e.g.:

from sqlalchemy import event

@event.listens_for(MyClass.collection, 'append', propagate=True)
def my_append_listener(target, value, initiator):
    print("received append event for target: %s" % target)

Listeners have the option to return a possibly modified version of the value, when the :paramref:`.AttributeEvents.retval` flag is passed to .event.listen or .event.listens_for:

def validate_phone(target, value, oldvalue, initiator):
    "Strip non-numeric characters from a phone number"

    return re.sub(r'\D', '', value)

# setup listener on UserContact.phone attribute, instructing
# it to use the return value
listen(UserContact.phone, 'set', validate_phone, retval=True)

A validation function like the above can also raise an exception such as ValueError to halt the operation.

The :paramref:`.AttributeEvents.propagate` flag is also important when applying listeners to mapped classes that also have mapped subclasses, as when using mapper inheritance patterns:

@event.listens_for(MySuperClass.attr, 'set', propagate=True)
def receive_set(target, value, initiator):
    print("value set: %s" % target)

The full list of modifiers available to the .event.listen and .event.listens_for functions are below.

Parameters
active_history=​FalseWhen True, indicates that the "set" event would like to receive the "old" value being replaced unconditionally, even if this requires firing off database loads. Note that active_history can also be set directly via .column_property and _orm.relationship.
propagate=​FalseWhen True, the listener function will be established not just for the class attribute given, but for attributes of the same name on all current subclasses of that class, as well as all future subclasses of that class, using an additional listener that listens for instrumentation events.
raw=​FalseWhen True, the "target" argument to the event will be the .InstanceState management object, rather than the mapped instance itself.
retval=​Falsewhen True, the user-defined event listening must return the "value" argument from the function. This gives the listening function the opportunity to change the value that is ultimately used for a "set" or "append" event.
Class Method ​_accept​_with Undocumented
Class Method ​_listen Undocumented
Static Method ​_set​_dispatch Undocumented
Method append Receive a collection append event.
Method append​_wo​_mutation Receive a collection append event where the collection was not actually mutated.
Method bulk​_replace Receive a collection 'bulk replace' event.
Method dispose​_collection Receive a 'collection dispose' event.
Method init​_collection Receive a 'collection init' event.
Method init​_scalar Receive a scalar "init" event.
Method modified Receive a 'modified' event.
Method remove Receive a collection remove event.
Method set Receive a scalar set event.
Class Variable ​_target​_class​_doc Undocumented

Inherited from Events:

Class Method ​_clear Undocumented
Class Method ​_remove Undocumented
@classmethod
def _accept_with(cls, target):
@classmethod
def _listen(cls, event_key, active_history=False, raw=False, retval=False, propagate=False):

Undocumented

@staticmethod
def _set_dispatch(cls, dispatch_cls):
def append(self, target, value, initiator):

Receive a collection append event.

The append event is invoked for each element as it is appended to the collection. This occurs for single-item appends as well as for a "bulk replace" operation.

See Also

.AttributeEvents - background on listener options such as propagation to subclasses.

.AttributeEvents.bulk_replace

Parameters
targetthe object instance receiving the event. If the listener is registered with raw=True, this will be the .InstanceState object.
valuethe value being appended. If this listener is registered with retval=True, the listener function must return this value, or a new value which replaces it.
initiatorAn instance of .attributes.Event representing the initiation of the event. May be modified from its original value by backref handlers in order to control chained event propagation, as well as be inspected for information about the source of the event.
Returns
if the event was registered with retval=True, the given value, or a new effective value, should be returned.
def append_wo_mutation(self, target, value, initiator):

Receive a collection append event where the collection was not actually mutated.

This event differs from _orm.AttributeEvents.append in that it is fired off for de-duplicating collections such as sets and dictionaries, when the object already exists in the target collection. The event does not have a return value and the identity of the given object cannot be changed.

The event is used for cascading objects into a _orm.Session when the collection has already been mutated via a backref event.

New in version 1.4.15.
Parameters
targetthe object instance receiving the event. If the listener is registered with raw=True, this will be the .InstanceState object.
valuethe value that would be appended if the object did not already exist in the collection.
initiatorAn instance of .attributes.Event representing the initiation of the event. May be modified from its original value by backref handlers in order to control chained event propagation, as well as be inspected for information about the source of the event.
Returns
No return value is defined for this event.
def bulk_replace(self, target, values, initiator):

Receive a collection 'bulk replace' event.

This event is invoked for a sequence of values as they are incoming to a bulk collection set operation, which can be modified in place before the values are treated as ORM objects. This is an "early hook" that runs before the bulk replace routine attempts to reconcile which objects are already present in the collection and which are being removed by the net replace operation.

It is typical that this method be combined with use of the .AttributeEvents.append event. When using both of these events, note that a bulk replace operation will invoke the .AttributeEvents.append event for all new items, even after .AttributeEvents.bulk_replace has been invoked for the collection as a whole. In order to determine if an .AttributeEvents.append event is part of a bulk replace, use the symbol ~.attributes.OP_BULK_REPLACE to test the incoming initiator:

from sqlalchemy.orm.attributes import OP_BULK_REPLACE

@event.listens_for(SomeObject.collection, "bulk_replace")
def process_collection(target, values, initiator):
    values[:] = [_make_value(value) for value in values]

@event.listens_for(SomeObject.collection, "append", retval=True)
def process_collection(target, value, initiator):
    # make sure bulk_replace didn't already do it
    if initiator is None or initiator.op is not OP_BULK_REPLACE:
        return _make_value(value)
    else:
        return value
New in version 1.2.

See Also

.AttributeEvents - background on listener options such as propagation to subclasses.

Parameters
targetthe object instance receiving the event. If the listener is registered with raw=True, this will be the .InstanceState object.
valuesUndocumented
initiatorAn instance of .attributes.Event representing the initiation of the event.
valuea sequence (e.g. a list) of the values being set. The handler can modify this list in place.
def dispose_collection(self, target, collection, collection_adapter):

Receive a 'collection dispose' event.

This event is triggered for a collection-based attribute when a collection is replaced, that is:

u1.addresses.append(a1)

u1.addresses = [a2, a3]  # <- old collection is disposed

The old collection received will contain its previous contents.

Changed in version 1.2: The collection passed to .AttributeEvents.dispose_collection will now have its contents before the dispose intact; previously, the collection would be empty.
New in version 1.0.0: the .AttributeEvents.init_collection and .AttributeEvents.dispose_collection events.

See Also

.AttributeEvents - background on listener options such as propagation to subclasses.

def init_collection(self, target, collection, collection_adapter):

Receive a 'collection init' event.

This event is triggered for a collection-based attribute, when the initial "empty collection" is first generated for a blank attribute, as well as for when the collection is replaced with a new one, such as via a set event.

E.g., given that User.addresses is a relationship-based collection, the event is triggered here:

u1 = User()
u1.addresses.append(a1)  #  <- new collection

and also during replace operations:

u1.addresses = [a2, a3]  #  <- new collection
New in version 1.0.0: .AttributeEvents.init_collection and .AttributeEvents.dispose_collection events.

See Also

.AttributeEvents - background on listener options such as propagation to subclasses.

.AttributeEvents.init_scalar - "scalar" version of this event.

Parameters
targetthe object instance receiving the event. If the listener is registered with raw=True, this will be the .InstanceState object.
collectionthe new collection. This will always be generated from what was specified as :paramref:`_orm.relationship.collection_class`, and will always be empty.
collection​_adapterthe .CollectionAdapter that will mediate internal access to the collection.
def init_scalar(self, target, value, dict_):

Receive a scalar "init" event.

This event is invoked when an uninitialized, unpersisted scalar attribute is accessed, e.g. read:

x = my_object.some_attribute

The ORM's default behavior when this occurs for an un-initialized attribute is to return the value None; note this differs from Python's usual behavior of raising AttributeError. The event here can be used to customize what value is actually returned, with the assumption that the event listener would be mirroring a default generator that is configured on the Core _schema.Column object as well.

Since a default generator on a _schema.Column might also produce a changing value such as a timestamp, the .AttributeEvents.init_scalar event handler can also be used to set the newly returned value, so that a Core-level default generation function effectively fires off only once, but at the moment the attribute is accessed on the non-persisted object. Normally, no change to the object's state is made when an uninitialized attribute is accessed (much older SQLAlchemy versions did in fact change the object's state).

If a default generator on a column returned a particular constant, a handler might be used as follows:

SOME_CONSTANT = 3.1415926

class MyClass(Base):
    # ...

    some_attribute = Column(Numeric, default=SOME_CONSTANT)

@event.listens_for(
    MyClass.some_attribute, "init_scalar",
    retval=True, propagate=True)
def _init_some_attribute(target, dict_, value):
    dict_['some_attribute'] = SOME_CONSTANT
    return SOME_CONSTANT

Above, we initialize the attribute MyClass.some_attribute to the value of SOME_CONSTANT. The above code includes the following features:

  • By setting the value SOME_CONSTANT in the given dict_, we indicate that this value is to be persisted to the database. This supersedes the use of SOME_CONSTANT in the default generator for the _schema.Column. The active_column_defaults.py example given at :ref:`examples_instrumentation` illustrates using the same approach for a changing default, e.g. a timestamp generator. In this particular example, it is not strictly necessary to do this since SOME_CONSTANT would be part of the INSERT statement in either case.
  • By establishing the retval=True flag, the value we return from the function will be returned by the attribute getter. Without this flag, the event is assumed to be a passive observer and the return value of our function is ignored.
  • The propagate=True flag is significant if the mapped class includes inheriting subclasses, which would also make use of this event listener. Without this flag, an inheriting subclass will not use our event handler.

In the above example, the attribute set event .AttributeEvents.set as well as the related validation feature provided by _orm.validates is not invoked when we apply our value to the given dict_. To have these events to invoke in response to our newly generated value, apply the value to the given object as a normal attribute set operation:

SOME_CONSTANT = 3.1415926

@event.listens_for(
    MyClass.some_attribute, "init_scalar",
    retval=True, propagate=True)
def _init_some_attribute(target, dict_, value):
    # will also fire off attribute set events
    target.some_attribute = SOME_CONSTANT
    return SOME_CONSTANT

When multiple listeners are set up, the generation of the value is "chained" from one listener to the next by passing the value returned by the previous listener that specifies retval=True as the value argument of the next listener.

New in version 1.1.

See Also

.AttributeEvents.init_collection - collection version of this event

.AttributeEvents - background on listener options such as propagation to subclasses.

:ref:`examples_instrumentation` - see the active_column_defaults.py example.

Parameters
targetthe object instance receiving the event. If the listener is registered with raw=True, this will be the .InstanceState object.
valuethe value that is to be returned before this event listener were invoked. This value begins as the value None, however will be the return value of the previous event handler function if multiple listeners are present.
dict​_the attribute dictionary of this mapped object. This is normally the __dict__ of the object, but in all cases represents the destination that the attribute system uses to get at the actual value of this attribute. Placing the value in this dictionary has the effect that the value will be used in the INSERT statement generated by the unit of work.
def modified(self, target, initiator):

Receive a 'modified' event.

This event is triggered when the .attributes.flag_modified function is used to trigger a modify event on an attribute without any specific value being set.

New in version 1.2.

See Also

.AttributeEvents - background on listener options such as propagation to subclasses.

Parameters
targetthe object instance receiving the event. If the listener is registered with raw=True, this will be the .InstanceState object.
initiatorAn instance of .attributes.Event representing the initiation of the event.
def remove(self, target, value, initiator):

Receive a collection remove event.

See Also

.AttributeEvents - background on listener options such as propagation to subclasses.

Parameters
targetthe object instance receiving the event. If the listener is registered with raw=True, this will be the .InstanceState object.
valuethe value being removed.
initiator

An instance of .attributes.Event representing the initiation of the event. May be modified from its original value by backref handlers in order to control chained event propagation.

Changed in version 0.9.0: the initiator argument is now passed as a .attributes.Event object, and may be modified by backref handlers within a chain of backref-linked events.
Returns
No return value is defined for this event.
def set(self, target, value, oldvalue, initiator):

Receive a scalar set event.

See Also

.AttributeEvents - background on listener options such as propagation to subclasses.

Parameters
targetthe object instance receiving the event. If the listener is registered with raw=True, this will be the .InstanceState object.
valuethe value being set. If this listener is registered with retval=True, the listener function must return this value, or a new value which replaces it.
oldvaluethe previous value being replaced. This may also be the symbol NEVER_SET or NO_VALUE. If the listener is registered with active_history=True, the previous value of the attribute will be loaded from the database if the existing value is currently unloaded or expired.
initiator

An instance of .attributes.Event representing the initiation of the event. May be modified from its original value by backref handlers in order to control chained event propagation.

Changed in version 0.9.0: the initiator argument is now passed as a .attributes.Event object, and may be modified by backref handlers within a chain of backref-linked events.
Returns
if the event was registered with retval=True, the given value, or a new effective value, should be returned.
_target_class_doc: str =

Undocumented