Package

pghistory

class pghistory.AfterInsert(label=None, condition=None)[source]

For events that happen after a database insert

class pghistory.AfterInsertOrUpdate(label=None, condition=None)[source]

A database event that happens after insert/update

class pghistory.AfterUpdate(label=None, condition=None)[source]

For events that happen 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 events that happen before a database deletion.

class pghistory.BeforeUpdate(label=None, condition=None)[source]

For events that happen before a database update. The OLD values of the row will be snapshot to the event 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 of pghistory.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 call pghistory.context as a function without entering it. The metadata set in the function call will be part of the context if pghistory.context has previously been entered. Otherwise it will be ignored.

Usage:

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’)

Parameters

metadata (dict) – Metadata that should be attached to the tracking context

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
  • obj (models.Model) – An instance of a model.

  • label (str) – The event label.

Raises

ValueError – If the event label has not been registered for the model.

Returns

The created event model.

Return type

models.Model

class pghistory.DatabaseEvent(label=None, when=None, condition=None, operation=None, snapshot=None)[source]

For tracking an event automatically based on database changes.

setup(event_model)[source]

Set up the event for the particular event model

pghistory.get_event_model(model, *events, fields=None, exclude=None, obj_fk=<object object>, context_fk=<object object>, related_name=None, name=None, app_label=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 original model.

Usage:

class MyEventModel(get_event_model(

TrackedModel, pghistory.AfterInsert(‘model_create’),

)):

# Add custom indices or change default field declarations…

Parameters
  • model (models.Model) – The model that is being tracked.

  • *events (List[Event]) – See “events” help from pghistory.track.

  • fields (List[str], default=None) – See “fields” help from pghistory.track.

  • exclude (List[str], default=None) – See “exclude” help from pghistory.track.

  • obj_fk (models.ForeignKey) – See “obj_fk” help from pghistory.track.

  • related_name (str, default=None) – See “related_name” help from pghistory.track.

  • name (str, default=None) – See “model_name” help from pghistory.track.

  • app_label (str, default=None) – See “app_label” help from pghistory.track.

  • abstract (bool, default=True) – True if the generated model should be an abstract model.

class pghistory.Snapshot(label=None)[source]

A special database event that tracks changes to fields. A snapshot event always fires for an insert and also fires for updates when any fields change.

NOTE: Two triggers must be 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.

setup(event_model)[source]

Set up the event for the particular event model

class pghistory.Event(label=None)[source]

For storing an event when a condition happens on a model

Events that inherit this base class are assumed to be manually created by the user. Only a “label” for the event is required.

Events that are automatically created in a Postgres trigger should inherit DatabaseEvent

setup(event_model)[source]

Set up the event for the particular event model

pghistory.track(*events, fields=None, exclude=None, obj_fk=<object object>, context_fk=<object object>, related_name=None, model_name=None, app_label=None)[source]

A decorator for tracking events for a mdoel.

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
  • *events (List[Event]) – The events to track. When using any event that inherits pghistory.DatabaseEvent, such as pghistory.AfterInsert, a Postgres trigger will be installed that automatically tracks the event with a generated event model. Events that do not inherit pghistory.DatabaseEvent are assumed to be manually tracked 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 the DatabaseEvent 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_fk (models.ForeignKey, default=unset) – The foreign key field that references the eventged object. Defaults to a non-nullable foreign key that cascade deletes. Use None to create a event model with no reference to the tracked object. See related_name attribute for how the related_name is determined.

  • context_fk (models.ForeignKey, default=unset) – The foreign key to tracked context, if any. Use None to avoid attaching historical context altogether.

  • related_name (str, default=None) – The related name of the event model. If not provided, defaults to “event” if one is tracking changes to the entire model, otherwise defaults to a name based on the combination of fields.

  • 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.

pghistory.middleware.HistoryMiddleware(get_response)[source]

Tracks POST requests and 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.

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.AggregateEventQuery(*args, **kwargs)[source]

A query over an aggregate event CTE

chain(klass=None)[source]

Return a copy of the current Query that’s ready for another operation. The klass argument changes the type of the Query, e.g. UpdateQuery.

get_compiler(using=None, connection=None)[source]

Overrides the Query method get_compiler in order to return an AggregateEventCompiler.

Copies the body of Django’s get_compiler and overrides the return, so we ignore covering this method.

class pghistory.models.AggregateEventQuerySet(model=None, query=None, using=None, hints=None)[source]

QuerySet with support for Common Table Expressions

across(*event_models)[source]

Aggregates events across the provided event models

target(obj)[source]

Target an object to aggregate events against

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()[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.apps after migration

class pghistory.models.Event(*args, **kwargs)[source]

An abstract model for base elements of a event

classmethod pghistory_setup()[source]

Called when the class is prepared (see apps.py) to finalize setup of the model and register triggers

pghistory.models.create_event_model(base_class, tracked_model, fields=None, exclude=None, obj_fk=<object object>, context_fk=<object object>, abstract=True, related_name=None, name=None, app_label=None, attrs=None, meta=None)[source]

The primary factory function for dynamically creating a history model.

Parameters
  • base_class (models.Model) – The base class from which the created model will inherit

  • tracked_model (models.Model) – The model being tracked

  • fields (List[str], default=None) – The fields to track. If None, all fields on tracked_model are tracked.

  • exclude (List[str], default=None) – If no fields are provided, exclude these fields from tracking.

  • obj_fk (models.ForeignKey, default=unset) – For overriding the foreign key that references the tracked object. If unset, defaults to a non-nullable foreign key that cascades. The related name defaults to related_name if all fields are tracked. Otherwise defaults to a combintion of related_name and fields. Use None to create a tracking model without a foreign key to the tracked model.

  • context_fk (models.ForeignKey, default=unset) – The foreign key to tracked context, if any. Use None to avoid attaching historical context altogether.

  • abstract (bool, default=True) – True if the created model should be abstract

  • related_name (str) – The primary way to identify the relation of the created model and the tracked model

  • name (str, default=None) – The name of the created model. If None, defaults to a combination of the related_name, tracked_model, and fields.

  • app_label (str, default=None) – The app_label for the created model. Defaults to the app_label of 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 for the tracking model.

  • attrs (dict, default=None) – Additional attributes to add to the created model.

  • meta (dict, default=None) – Additional options to add to the model Meta