Module¶
pghistory¶
- class pghistory.AfterInsert(label=None, *, condition=None)[source]¶
For trackers that fire after a database insert
- class pghistory.AfterInsertOrUpdate(label=None, *, condition=None)[source]¶
A database tracker that happens after insert/update
- class pghistory.AfterUpdate(label=None, *, condition=None)[source]¶
For trackers that fire after a database update. The NEW values of the row will be snapshot to the event model
- class pghistory.BeforeDelete(label=None, *, condition=None)[source]¶
For trackers that fire before a database deletion.
- class pghistory.BeforeUpdate(label=None, *, condition=None)[source]¶
For trackers that fire before a database update. The OLD values of the row will be snapshot to the event model
- class pghistory.BeforeUpdateOrDelete(label=None, *, condition=None)[source]¶
A database tracker that snapshots the old row during an update or delete
- class pghistory.Changed(event_model, exclude=None)[source]¶
A utilty to create conditions based on changes in the tracked model.
Given the event model, we create a condition as follows:
If the event model trackes every field from the main model, we can use a standard
OLD.* IS DISTINCT FROM NEW.*
condition to snapshot every change on the main model.If the event model tracks a subset of the fields of the main model, only changes to event fields will trigger a snapshot. In other words, if the main model has an int and char field, but the event model only tracks the char field, the condition will be
OLD.char_field IS DISTINCT FROM NEW.char_field
.If one has fields on the event model and wishes to ignore them from triggering snapshots, pass them to the
exclude
argument to this utility.
- class pghistory.ContextForeignKey(*, null=True, related_query_name=<object object>, **kwargs)[source]¶
Configuration for the
pgh_context
field when a foreign key is used.Overrides null to
True
.
- class pghistory.ContextJSONField(*, null=True, **kwargs)[source]¶
Configuration for the
pgh_context
field when denormalized context is used.
- class pghistory.ContextUUIDField(*, null=True, **kwargs)[source]¶
Configuration for the
pgh_context_id
field when denormalized context is used.
- class pghistory.DatabaseEvent(label=None, *, when=None, condition=None, operation=None, snapshot=None)[source]¶
The deprecated base class for all trigger-based trackers. Use
DatabaseTracker
instead.
- class pghistory.DatabaseTracker(label=None, *, when=None, condition=None, operation=None, snapshot=None)[source]¶
For tracking an event automatically based on database changes.
- class pghistory.Event(label=None)[source]¶
The deprecated base class for event trackers. Use
Tracker
instead
- class pghistory.Field(*, primary_key=<object object>, unique=<object object>, blank=<object object>, null=<object object>, db_index=<object object>, editable=<object object>, unique_for_date=<object object>, unique_for_month=<object object>, unique_for_year=<object object>)[source]¶
Configuration for fields.
Provides these default parameters:
primary_key (default=False)
unique (default=False)
blank
null
db_index (default=False)
editable
unique_for_date (default=None)
unique_for_month (default=None)
unique_for_year (default=None)
The default values for the above parameters ensure that event models don’t have unnecessary uniqueness constraints carried over from the tracked model.
- class pghistory.ForeignKey(*, on_delete=<object object>, db_constraint=<object object>, **kwargs)[source]¶
Configuration for foreign keys.
The following parameters can be used:
on_delete (default=models.DO_NOTHING)
db_constraint (default=False)
Arguments for
RelatedField
andField
can also be supplied. Note that db_index is overridden toTrue
for all foreign keys
- class pghistory.ObjForeignKey(*, related_name=<object object>, related_query_name=<object object>, **kwargs)[source]¶
Configuration for the
pgh_obj
field
- pghistory.ProxyField(proxy, field)[source]¶
Proxies a JSON field from a model and adds it as a field in the queryset.
- Parameters
proxy (str) – The value to proxy, e.g. “user__email”
field (Type[django.models.Field]) – The field that will be used to cast the resulting value
- class pghistory.RelatedField(*, related_name=<object object>, related_query_name=<object object>, **kwargs)[source]¶
Configuration for related fields.
The following parameters can be used to configure defaults for all related fields:
related_name (default=”+”)
related_query_name (default=”+”)
By default, related names are stripped to avoid unnecessary clashes.
Note that all arguments from
Field
can also be supplied.
- class pghistory.Snapshot(label=None, delayed=False)[source]¶
Tracks changes to fields. A snapshot tracker tracks inserts and updates. It ensures that no duplicate rows are created with a pre-configured condition.
NOTE: Two triggers are created since Insert triggers do not allow comparison against the OLD values. We could also place this in one trigger and do the condition in the plpgsql code.
- class pghistory.Tracker(label=None)[source]¶
For tracking an event when a condition happens on a model.
- class pghistory.context(**metadata)[source]¶
A context manager that groups changes under the same context and adds additional metadata about the event.
Context is added as variables at the beginning of every SQL statement. By default, all variables are localized to the transaction (i.e SET LOCAL), meaning they will only persist for the statement/transaction and not across the session.
Once any code has entered
pghistory.context
, all subsequent entrances ofpghistory.context
will be grouped under the same context until the top-most parent exits.To add context only if a parent has already entered
pghistory.context
, one can callpghistory.context
as a function without entering it. The metadata set in the function call will be part of the context ifpghistory.context
has previously been entered. Otherwise it will be ignored.- Parameters
**metadata – Metadata that should be attached to the tracking context
Example
Here we track a “key” with a value of “value”:
with pghistory.context(key='value'): # Do things.. # All tracked events will have the same ``pgh_context`` # foreign key, and the context object will include # {'key': 'value'} in its metadata. # Nesting the tracker adds additional metadata to the current # context # Add metadata if a parent piece of code has already entered # pghistory.context pghistory.context(key='value')
Notes
Context tracking is compatible for most scenarios, but it currently does not work for named cursors. Django uses named cursors for the .iterator() operator, which has no effect on history tracking. However, there may be other usages of named cursors in Django where history context is ignored.
- pghistory.create_event(obj, *, label, using='default')[source]¶
Manually create a event for an object.
Events are automatically linked with any context being tracked via
pghistory.context
.- Parameters
- Raises
ValueError – If the event label has not been registered for the model.
- Returns
The created event model.
- Return type
models.Model
- pghistory.create_event_model(tracked_model, *trackers, fields=None, exclude=None, obj_fk=<object object>, context_fk=<object object>, obj_field=<object object>, context_field=<object object>, context_id_field=<object object>, related_name=None, name=None, model_name=None, app_label=None, base_model=None, attrs=None, meta=None, abstract=True)[source]¶
Obtain a base event model.
Instead of using
pghistory.track
, which dynamically generates an event model, one can instead construct a event model themselves, which will also set up event tracking for the tracked model.- Parameters
tracked_model (models.Model) – The model that is being tracked.
*trackers (List[
Tracker
]) – The event trackers. When using any tracker that inheritspghistory.DatabaseTracker
, such aspghistory.AfterInsert
, a Postgres trigger will be installed that automatically tracks the event with a generated event model. Trackers that do not inheritpghistory.DatabaseTracker
are assumed to have manual events created by the user.fields (List[str], default=None) – The list of fields to snapshot when the event takes place. When no fields are provided, the entire model is snapshot when the event happens. Note that snapshotting of the OLD or NEW row is configured by the
snapshot
attribute of theDatabaseTracker
object. Manual events must specify these fields during manual creation.exclude (List[str], default=None) – Instead of providing a list of fields to snapshot, a user can instead provide a list of fields to not snapshot.
obj_field (pghistory.ObjForeignKey, default=unset) – The foreign key field configuration that references the tracked object. Defaults to an unconstrained non-nullable foreign key. Use
None
to create a event model with no reference to the tracked object.context_field (Union[pghistory.ContextForeignKey, pghistory.ContextJSONField], default=unset) – The context field configuration. Defaults to a nullable unconstrained foreign key. Use
None
to avoid attaching historical context altogether.context_id_field (pghistory.ContextUUIDField, default=unset) – The context ID field configuration when using a ContextJSONField for the context_field. When using a denormalized context field, the ID field is used to track the UUID of the context. Use
None
to avoid using this field for denormalized context.model_name (str, default=None) – Use a custom model name when the event model is generated. Otherwise a default name based on the tracked model and fields will be created.
app_label (str, default=None) – The app_label for the generated event model. Defaults to the app_label of the tracked model. Note, when tracking a Django model (User) or a model of a third-party app, one must manually specify the app_label of an internal app to use so that migrations work properly.
base_model (models.Model, default=pghistory.models.Event) – The base model for the event model. Must inherit pghistory.models.Event.
attrs (dict, default=None) – Additional attributes to add to the event model
meta (dict, default=None) – Additional attributes to add to the Meta class of the event model.
abstract (bool, default=True) –
True
if the generated model should be an abstract model.
Example
Create a manual event model:
class MyEventModel(create_event_model( TrackedModel, pghistory.AfterInsert('model_create'), )): # Add custom indices or change default field declarations...
- pghistory.track(*trackers, fields=None, exclude=None, obj_fk=<object object>, context_fk=<object object>, obj_field=<object object>, context_field=<object object>, context_id_field=<object object>, related_name=None, model_name=None, app_label=None, base_model=None, attrs=None, meta=None)[source]¶
A decorator for tracking events for a model.
When using this decorator, an event model is dynamically generated that snapshots the entire model or supplied fields of the model based on the
events
supplied. The snapshot is accompanied with the label that identifies the event.- Parameters
*trackers (List[
Tracker
]) – The event trackers. When using any tracker that inheritspghistory.DatabaseTracker
, such aspghistory.AfterInsert
, a Postgres trigger will be installed that automatically tracks the event with a generated event model. Trackers that do not inheritpghistory.DatabaseTracker
are assumed to have manual events created by the user.fields (List[str], default=None) – The list of fields to snapshot when the event takes place. When no fields are provided, the entire model is snapshot when the event happens. Note that snapshotting of the OLD or NEW row is configured by the
snapshot
attribute of theDatabaseTracker
object. Manual events must specify these fields during manual creation.exclude (List[str], default=None) – Instead of providing a list of fields to snapshot, a user can instead provide a list of fields to not snapshot.
obj_field (pghistory.ObjForeignKey, default=unset) – The foreign key field configuration that references the tracked object. Defaults to an unconstrained non-nullable foreign key. Use
None
to create a event model with no reference to the tracked object.context_field (Union[pghistory.ContextForeignKey, pghistory.ContextJSONField], default=unset) – The context field configuration. Defaults to a nullable unconstrained foreign key. Use
None
to avoid attaching historical context altogether.context_id_field (pghistory.ContextUUIDField, default=unset) – The context ID field configuration when using a ContextJSONField for the context_field. When using a denormalized context field, the ID field is used to track the UUID of the context. Use
None
to avoid using this field for denormalized context.model_name (str, default=None) – Use a custom model name when the event model is generated. Otherwise a default name based on the tracked model and fields will be created.
app_label (str, default=None) – The app_label for the generated event model. Defaults to the app_label of the tracked model. Note, when tracking a Django model (User) or a model of a third-party app, one must manually specify the app_label of an internal app to use so that migrations work properly.
base_model (models.Model, default=`pghistory.models.Event`) – The base model for the event model. Must inherit
pghistory.models.Event
.attrs (dict, default=None) – Additional attributes to add to the event model
meta (dict, default=None) – Additional attributes to add to the Meta class of the event model.
pghistory.admin¶
- class pghistory.admin.EventsAdmin(model, admin_site)[source]¶
- get_changelist(request, **kwargs)[source]¶
Return the ChangeList class for use on the changelist page.
- get_list_display(request)[source]¶
Return a sequence containing the fields to be displayed on the changelist.
pghistory.middleware¶
- pghistory.middleware.HistoryMiddleware(get_response)[source]¶
Annotates the user/url in the pghistory context.
- class pghistory.middleware.WSGIRequest(environ)[source]¶
Although Django’s auth middleware sets the user in middleware, apps like django-rest-framework set the user in the view layer. This creates issues for pghistory tracking since the context needs to be set before DB operations happen.
This special WSGIRequest updates pghistory context when the request.user attribute is updated.
pghistory.models¶
- class pghistory.models.AggregateEvent(*args, **kwargs)[source]¶
A proxy model for aggregating events together across tables and rendering diffs
- exception DoesNotExist¶
- exception MultipleObjectsReturned¶
- class pghistory.models.BaseAggregateEvent(*args, **kwargs)[source]¶
A proxy model for aggregating events together across tables and rendering diffs
- class pghistory.models.Context(id, created_at, updated_at, metadata)[source]¶
- exception DoesNotExist¶
- exception MultipleObjectsReturned¶
- classmethod install_pgh_attach_context_func(using='default')[source]¶
Installs a custom store procedure for upserting context for historical events. The upsert is aware of when tracking is enabled in the app (i.e. using pghistory.context())
This stored procedure is automatically installed in pghistory migration 0004.
- class pghistory.models.Event(*args, **kwargs)[source]¶
An abstract model for base elements of a event
- property can_revert¶
True if the event model can revert the tracked model
- classmethod check(**kwargs)[source]¶
Allow proxy models to inherit this model and define their own fields that are dynamically pulled from context
- class pghistory.models.EventQuery(model, where=<class 'django.db.models.sql.where.WhereNode'>, alias_cols=True)[source]¶
A query over an event CTE when proxy fields are used
- class pghistory.models.EventQuerySet(model=None, query=None, using=None, hints=None)[source]¶
QuerySet with support for proxy fields
- class pghistory.models.Events(*args, **kwargs)[source]¶
A proxy model for aggregating events together across tables and rendering diffs
- exception DoesNotExist¶
- exception MultipleObjectsReturned¶
- class pghistory.models.EventsQuerySet(model=None, query=None, using=None, hints=None)[source]¶
QuerySet with support for Common Table Expressions
- class pghistory.models.MiddlewareEvents(*args, **kwargs)[source]¶
A proxy model for aggregating events. Includes additional fields that are captured by the pghistory middleware
- exception DoesNotExist¶
- exception MultipleObjectsReturned¶
- class pghistory.models.NoObjectsManager(*args, **kwargs)[source]¶
Django’s dumpdata and other commands will not work with Events models by default because of how they aggregate multiple tables based on objects.
We use this as the default manager for aggregate events so that dumpdata and other management commands still work with these models