Advanced features¶
The Quick start section showed you how to log, track and retrieve activity related to given instances.
This section provides more details on django-actrack
basic workflow and
presents some of its more advanced features.
Action creation parameters¶
Check the API documentation for actrack.log to learn more about the additional parameters that it can accept.
Action handlers¶
For each action you are using in your code, you can create a subclass of
actrack.ActionHandler
with a corresponding verb
class attribute that
will be related to this action. An instance of this handler class will be
attached to any Action
object that is created or retrieved, as the
handler
attribute:
from actrack import ActionHandler
class MyActionHandler(ActionHandler):
verb = 'my_action'
def render(self, context):
return 'I did that'
def do_something(self):
for t in self.action.targets.all():
do_something_with_this_target(t)
Handlers are used to process the action. The only special methods are:
- render
- Called when you call
render
on an Action instance. See Rendering- get_text
- Returns the text associated to the action
- get_timeinfo
- Returns the time info of the action
- get_context
- Returns a default rendering context for the action, should you need it for template rendering
- combine(kwargs) [classmethod]
- See Combination
- group(newer_kw, older_kw) [classmethod]
- See Grouping
See the actrack.handler module for default implementations.
You can of course override any of the above methods in the ActionHandler
subclasses if you need to customise how certain actions should be rendered or
combined.
Combination¶
Sometimes, actions should be combined. Either because 2 same actions with different arguments occurred at the same time, because two actions are redundant and should be merged, or for whatever app-dependant reason.
Only actions with the same actor and targets can be combined.
Action handlers can define custom combine_with_[verb]
methods that
determine what to do when a verb
action is already in the queue. The method
takes the keyword arguments that would be passed to the ‘Action’
constructor, and can make use of self.queue
, a registry of all the
previously added keyword arguments in this request. When this method returns
True
, the currently logged action is discarded. In this case, it is the
responsibility of combine_with_[verb]
to amend the action to which the
discarded action is combined.
Note that the combination occurs when the action is logged. If an action is combined / discarded, it is not placed into the queue. The queue is saved to the database when a request finishes, after Grouping takes place.
Grouping¶
When the same action is repeated over a number of objects or on the same object, it is useless to show very similar actions a number of times.
django-actrack
provides a way to check if an action that is being logged
is similar to recent actions and, if it finds one, it amends it instead of
creating a new one.
The definition of ‘recent’ can be changed by the GROUPING_DELAY
setting, in
seconds. Individually, it is also possible to change this delay or disable
action grouping when calling actrack.log
using the grouping_delay
argument.
By default, an action is considered ‘similar’ if it has the same actor, and at
least the same targets or related objects. This can be customized by
overriding the group
method in the ActionHandler
subclass relative to
the relevant action.
Grouping only occurs when the action queue is saved.
Deleted items¶
This is a great feature of django-actrack
. If an object to which an action
is related (the object can be the actor, a target or related object) is
deleted, the action itself can either be deleted (if passing
use_del_items=False
to actrack.connect
) or can remain. If it remains,
its reference to the deleted item is replaced by a reference to an instance of
a special model, that stores a verbose description of the deleted item.
For example, if the train
instance is deleted (retired from the railway
company’s network, for example), the actions that had been generated beforehand
refering to that train
will not be deleted, and one will still be able to
read when the train started and when it arrived.
To retrieve the verbose description, django-actrack
first looks for a
deleted_item_description
method, calls it with no arguments and takes the
returned string as the description. If that fails, it will simply evaluate
the instance as a string using str
.
The same thing exists for serialization. By default, the serialization
field of the deleted item instance is populated with {'pk': object.pk}
where object
is the object being deleted. The value stored in
serialization
can be customized on a per-instance basis using the
deleted_item_serialization
method.
Warning
If you are logging an action involving an instance while deleting it (typically within a pre_delete or post_delete signal handler), you need to turn it into a ‘deleted item’ first. This can be done using the function actrack.deletion.get_del_item which takes the instance as an argument and returns a deleted item instance. Be careful, get_del_item creates an entry for a deleted item in the database, so make sure you call it only when you are actually deleting an instance
Read / unread actions¶
When the TRACK_UNREAD
setting is set to True
,
django-actrack
can make the distinction between read and unread actions.
When a new action is created, it is simply considered ad unread by all users.
An action’s status can be retrieved using the Action.is_unread_for
method,
which takes a user as sole argument.
To update this status, you may use the Action.mark_read_for(user, force)
method. force
will override the AUTO_READ
setting.
Alternatively, if AUTO_READ
is True
, an action can be marked as read
when it is rendered, using its render
method.
There are also classmethods on Action
that implement the same functions on
a sequence of actions: bulk_is_unread_for
, bulk_mark_read_for
and
bulk_render
. All of them take an ordered sequence of actions as first
argument and return a list of booleans for the first two and strings for the
third.
Rendering¶
Speaking about rendering, any action can be rendered through its render
method. Action.render
calls the action handler’s render
method, that
can be overridden in subclasses of ActionHandler
.
The ActionHandler.get_context
method generates a useful default context
dictionary from the attached action data.