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 when view.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 at config.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 fire BeforeIndex and AfterIndex events but BeforeShow and AfterShow 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/after update 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.