Event Handlers¶
Nefertari event handler module includes a set of events, maps of events, event handler predicates and helper function to connect it all together. All the objects are contained in nefertari.events
module. Nefertari event handlers use Pyramid event system.
Events¶
nefertari.events
defines a set of event classes inherited from nefertari.events.RequestEvent
, nefertari.events.BeforeEvent
and nefertari.events.AfterEvent
.
- There are two types of nefertari events:
- “Before” events, which are run after view class is instantiated, but before view method is run, and before request is processed. Can be used to edit the request.
- “After” events, which are run after view method has been called. Can be used to edit the response.
Check the API section for a full list of attributes/params events have.
- Complete list of events:
- BeforeIndex
- BeforeShow
- BeforeCreate
- BeforeUpdate
- BeforeReplace
- BeforeDelete
- BeforeUpdateMany
- BeforeDeleteMany
- BeforeItemOptions
- BeforeCollectionOptions
- AfterIndex
- AfterShow
- AfterCreate
- AfterUpdate
- AfterReplace
- AfterDelete
- AfterUpdateMany
- AfterDeleteMany
- AfterItemOptions
- AfterCollectionOptions
All events are named after camel-cased name of view method they are called around and prefixed with “Before” or “After” depending on the place event is triggered from (as described above). E.g. event classed for view method update_many
are called BeforeUpdateMany
and AfterUpdateMany
.
Before vs After¶
- It is recommended to use
before
events to: - Transform input
- Perform validation
- Apply changes to object that is being affected by request using
event.set_field_value
method
- And
after
events to: - Change DB objects which are not affected by request
- Perform notifications/logging
- Edit a response using
event.set_field_value
method
Note: if a field changed via event.set_field_value
is not affected by the request, it will be added to event.fields
which will make any field processors attached to this field to be triggered, if they are run after this method call (connected to events after handler that performs method call).
Predicates¶
- nefertari.events.ModelClassIs
- Available under
model
param when connecting event handlers, it allows to connect event handlers on per-model basis. When event handler is connected using this predicate, it will only be called whenview.Model
is the same class or subclass of this param value.
Utilities¶
- nefertari.events.subscribe_to_events
- Helper function that allows to connect event handler to multiple events at once. Supports
model
event handler predicate param. Available atconfig.subscribe_to_events
. Subscribers are run in order connected. - nefertari.events.BEFORE_EVENTS
- Map of
{view_method_name: EventClass}
of “Before” events. E.g. one of its elements is'index': BeforeIndex
. - nefertari.events.AFTER_EVENTS
- Map of
{view_method_name: EventClass}
of “AFter” events. E.g. one of its elements is'index': AfterIndex
. - nefertari.events.silent
- Decorator which marks view class or view method as “silent”. Silent view classes and methods don’t fire events. In the example below, view
ItemsView
won’t fire any event.UsersView
won’t fireBeforeIndex
andAfterIndex
events butBeforeShow
andAfterShow
events will be fired.
from nefertari import view, events
@events.silent
class ItemsView(view.BaseView):
...
class UsersView(view.BaseView):
@events.silent
def index(self):
...
def show(self):
...
- nefertari.events.trigger_instead
- Decorator which allows view method to trigger another event instead of the default one. In the example above collection GET requests (
UsersView.index
) will trigger the event which corresponds to item PATCH (update
).
from nefertari import view, events
class UsersView(view.BaseView):
@events.trigger_instead('update')
def index(self):
...
Example¶
We will use the following example to demonstrate how to connect handlers to events. This handler logs request
to the console.
import logging
log = logging.getLogger(__name__)
def log_request(event):
log.debug(event.request.body)
We can connect this handler to any of Nefertari events of any requests. E.g. lets log all collection POST after requests are made (view create
method):
from nefertari import events
config.subscribe_to_events(
log_request, [events.AfterCreate])
Or, if we wanted to limit the models for which this handler should be called, we can connect it with a model
predicate:
from nefertari import events
from .models import User
config.subscribe_to_events(
log_request, [events.AfterCreate],
model=User)
This way, log_request
event handler will only be called when collection POST request comes at an endpoint which handles the User
model.
Whenever the response has to be edited, after
events with event.set_field_value
must be used. If the response contains a single item, calling this method will change this single item’s field. Otherwise field will be changed for all the objects in the response. To edit the response meta, you can access event.response
directly. event.response
is a view method response serialized into dict
.
E.g. if we want to hide user passwords from response on collection and item GET:
from nefertari import events
from .models import User
def hide_user_passwords(event):
# Hide 'password' field
event.set_field_value('password', 'VERY_SECRET')
config.subscribe_to_events(
hide_user_passwords,
[events.AfterIndex, events.AfterShow],
model=User)
API¶
-
class
nefertari.events.
RequestEvent
(model, view, fields=None, field=None, instance=None, response=None)¶ Nefertari request event.
Parameters: - model – Model class affected by the request
- view – View instance which will process the request. Some useful attributes are: request, _json_params, _query_params. Change _json_params to edit data used to create/update objects and _query_params to edit data used to query database.
- fields – Dict of all fields from request.json. Keys are fields names and values are nefertari.utils.FieldData instances. If request does not have JSON body, value will be an empty dict.
- field – Changed field object. This field is set/changed in FieldIsChanged subscriber predicate. Do not use this field to determine what event was triggered when same event handler was registered with and without field predicate.
- instance – Object instance affected by request. Used in item requests only(item GET, PATCH, PUT, DELETE). Should be used to read data only. Changes to the instance may result in database data inconsistency.
- response – Return value of view method serialized into dict. E.g. if view method returns “1”, value of event.response will be “1”. Is None in all “before” events. Note that is not a Pyramid Response instance but the value returned by view method. May be useful to access newly created object on “create” action if it is returned by view method.
-
class
nefertari.events.
ModelClassIs
(model, config)¶ Subscriber predicate to check event.model is the right model.
Example: config.add_subscriber(func, event, model=ModelCls)
-
nefertari.events.
subscribe_to_events
(config, subscriber, events, model=None)¶ Helper function to subscribe to group of events.
Parameters: - config – Pyramid contig instance.
- subscriber – Event subscriber function.
- events – Sequence of events to subscribe to.
- model – Model predicate value.
-
nefertari.events.
silent
(obj)¶ Mark view method or class as “silent” so events won’t be fired.
Should be used as decorator on view classes or methods.
Parameters: obj – Any object that allows attributes assignment. Should be either view method or view class.
-
nefertari.events.
trigger_instead
(event_action)¶ Specify action name to change event triggered by view method.
In the example above
MyView.index
method will trigger before/afterupdate
events.class MyView(BaseView): @events.trigger_instead('update') def index(self): (...)
Parameters: event_action – Event action name which should be triggered instead of default one.