Module
pghistory
pghistory.DEFAULT
module-attribute
For setting a configuration value back to its default value
pghistory.AfterInsert
pghistory.AfterInsertOrUpdate
pghistory.AfterUpdate
pghistory.BeforeDelete
pghistory.BeforeUpdate
pghistory.BeforeUpdateOrDelete
pghistory.Changed
Bases: Condition
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.
Source code in pghistory/core.py
pghistory.ContextForeignKey
ContextForeignKey(
*,
null: bool = True,
related_query_name: str = constants.DEFAULT,
**kwargs: Any
)
Bases: ForeignKey
Configuration for the pgh_context
field when a foreign key is used.
Overrides null to True
.
Attributes:
Name | Type | Description |
---|---|---|
null |
bool, default=True
|
True if nullable context is allowed |
related_query_name |
str
|
The related_query_name to use |
Source code in pghistory/config.py
pghistory.ContextJSONField
Bases: Field
Configuration for the pgh_context
field when denormalized context is used.
Attributes:
Name | Type | Description |
---|---|---|
null |
bool, default=True
|
True if nullable context is allowed |
Source code in pghistory/config.py
pghistory.ContextUUIDField
Bases: Field
Configuration for the pgh_context_id
field when denormalized context is used.
Attributes:
Name | Type | Description |
---|---|---|
null |
bool, default=True
|
True if nullable context is allowed |
Source code in pghistory/config.py
pghistory.DatabaseEvent
DatabaseEvent(
label: str = None,
*,
when: pgtrigger.When = None,
condition: Union[pgtrigger.Condition, None] = None,
operation: pgtrigger.Operation = None,
snapshot: str = None
)
Bases: DatabaseTracker
The deprecated base class for all trigger-based trackers.
Use DatabaseTracker
instead.
Source code in pghistory/core.py
pghistory.DatabaseTracker
DatabaseTracker(
label: str = None,
*,
when: pgtrigger.When = None,
condition: Union[pgtrigger.Condition, None] = None,
operation: pgtrigger.Operation = None,
snapshot: str = None
)
Bases: Tracker
For tracking an event automatically based on database changes.
Source code in pghistory/core.py
pghistory.Event
Bases: Tracker
The deprecated base class for event trackers. Use Tracker
instead
Source code in pghistory/core.py
pghistory.Field
Field(
*,
primary_key: bool = constants.UNSET,
unique: bool = constants.UNSET,
blank: bool = constants.UNSET,
null: bool = constants.UNSET,
db_index: bool = constants.UNSET,
editable: bool = constants.UNSET,
unique_for_date: bool = constants.UNSET,
unique_for_month: bool = constants.UNSET,
unique_for_year: bool = constants.UNSET
)
Configuration for fields.
The default values for the attributes ensure that event models don't have unnecessary uniqueness constraints carried over from the tracked model.
Attributes:
Name | Type | Description |
---|---|---|
primary_key |
bool, default=False
|
True if a primary key |
unique |
bool, default=False
|
True if unique |
blank |
bool
|
True if blank |
null |
bool
|
True if null |
db_index |
bool
|
True if indexed |
editable |
bool
|
True if editable |
unique_for_date |
bool
|
True if unique for date |
unique_for_month |
bool
|
True if unique for the month |
unique_for_year |
bool
|
True if unique for the year |
Source code in pghistory/config.py
pghistory.ForeignKey
ForeignKey(
*,
on_delete: Any = constants.UNSET,
db_constraint: bool = constants.UNSET,
**kwargs: Any
)
Bases: RelatedField
Configuration for foreign keys.
Arguments for RelatedField
and Field
can also be supplied.
Note that db_index is overridden to True
for all foreign keys
Attributes:
Name | Type | Description |
---|---|---|
on_delete |
default=models.DO_NOTHING
|
Django's on_delete property |
db_constraint |
bool, default=False
|
True to use a datbase constraint for the foreign key |
Source code in pghistory/config.py
pghistory.ManualTracker
pghistory.ObjForeignKey
ObjForeignKey(
*,
related_name: str = constants.DEFAULT,
related_query_name: str = constants.DEFAULT,
**kwargs
)
Bases: ForeignKey
Configuration for the pgh_obj
field
Attributes:
Name | Type | Description |
---|---|---|
related_name |
str
|
The related_name to use |
related_query_name |
str
|
The related_query_name to use |
Source code in pghistory/config.py
pghistory.RelatedField
RelatedField(
*,
related_name: str = constants.UNSET,
related_query_name: str = constants.UNSET,
**kwargs: Any
)
Bases: Field
Configuration for related fields.
By default, related names are stripped to avoid unnecessary clashes.
Note that all arguments from Field
can also be supplied.
Attributes:
Name | Type | Description |
---|---|---|
related_name |
str, default="+"
|
The related_name to use |
related_query_name |
str, default="+"
|
The related_query_name to use |
Source code in pghistory/config.py
pghistory.Snapshot
Bases: DatabaseTracker
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.
Source code in pghistory/core.py
pghistory.Tracker
For tracking an event when a condition happens on a model.
Source code in pghistory/core.py
pghistory_setup
Registers the tracker for the event model and calls user-defined setup
Source code in pghistory/core.py
pghistory.context
Bases: ContextDecorator
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.
Attributes:
Name | Type | Description |
---|---|---|
**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')
Note
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.
Source code in pghistory/runtime.py
pghistory.ProxyField
Proxies a JSON field from a model and adds it as a field in the queryset.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
proxy |
str
|
The value to proxy, e.g. "user__email" |
required |
field |
Type[Field]
|
The field that will be used to cast the resulting value |
required |
Source code in pghistory/core.py
pghistory.create_event
Manually create a event for an object.
Events are automatically linked with any context being tracked via pghistory.context.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
obj |
Model
|
An instance of a model. |
required |
label |
str
|
The event label. |
required |
using |
str
|
The database |
'default'
|
Raises:
Type | Description |
---|---|
ValueError
|
If the event label has not been registered for the model. |
Returns:
Type | Description |
---|---|
Model
|
The created event model object |
Source code in pghistory/core.py
pghistory.create_event_model
create_event_model(
tracked_model: Type[models.Model],
*trackers: Tracker,
fields: Union[List[str], None] = None,
exclude: Union[List[str], None] = None,
obj_fk: ObjForeignKey = constants.UNSET,
context_fk: Union[ContextForeignKey, ContextJSONField] = constants.UNSET,
obj_field: ObjForeignKey = constants.UNSET,
context_field: Union[ContextForeignKey, ContextJSONField] = constants.UNSET,
context_id_field: ContextUUIDField = constants.UNSET,
related_name: Union[str, None] = None,
name: Union[str, None] = None,
model_name: Union[str, None] = None,
app_label: Union[str, None] = None,
base_model: Type[models.Model] = None,
attrs: Dict[str, Any] = None,
meta: Dict[str, Any] = None,
abstract: bool = True
) -> Type[models.Model]
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:
Name | Type | Description | Default |
---|---|---|---|
tracked_model |
Type[Model]
|
The model that is being tracked. |
required |
*trackers |
Tracker
|
The event trackers. When using any tracker that inherits pghistory.DatabaseTracker, such as pghistory.AfterInsert, a Postgres trigger will be installed that automatically tracks the event with a generated event model. Trackers that do not inherit pghistory.DatabaseTracker are assumed to have manual events created by the user. |
()
|
fields |
Union[List[str], 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 |
None
|
exclude |
Union[List[str], None]
|
Instead of providing a list of fields to snapshot, a user can instead provide a list of fields to not snapshot. |
None
|
obj_fk |
ObjForeignKey
|
The old (and deprecated) object field. |
UNSET
|
context_fk |
Union[ContextForeignKey, ContextJSONField]
|
The old (and deprecated) context field. |
UNSET
|
obj_field |
ObjForeignKey
|
The foreign key field configuration that references the tracked object.
Defaults to an unconstrained non-nullable foreign key. Use |
UNSET
|
context_field |
Union[ContextForeignKey, ContextJSONField]
|
The context field configuration. Defaults to a nullable
unconstrained foreign key. Use |
UNSET
|
context_id_field |
ContextUUIDField
|
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 |
UNSET
|
related_name |
Union[str, None]
|
The old (and deprecated) related name field. |
None
|
name |
Union[str, None]
|
The old (and deprecated) model name field. |
None
|
model_name |
Union[str, 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. |
None
|
app_label |
Union[str, 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. |
None
|
base_model |
Type[Model]
|
The base model for the event model. Must inherit pghistory.models.Event. |
None
|
attrs |
Dict[str, Any]
|
Additional attributes to add to the event model |
None
|
meta |
Dict[str, Any]
|
Additional attributes to add to the Meta class of the event model. |
None
|
abstract |
bool
|
|
True
|
Returns:
Type | Description |
---|---|
Type[Model]
|
The event model class. |
Example
Create a manual event model:
class MyEventModel(create_event_model(
TrackedModel,
pghistory.AfterInsert('model_create'),
)):
# Add custom indices or change default field declarations...
Source code in pghistory/core.py
507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 |
|
pghistory.track
track(
*trackers: Tracker,
fields: Union[List[str], None] = None,
exclude: Union[List[str], None] = None,
obj_fk: ObjForeignKey = constants.UNSET,
context_fk: Union[ContextForeignKey, ContextJSONField] = constants.UNSET,
obj_field: ObjForeignKey = constants.UNSET,
context_field: Union[ContextForeignKey, ContextJSONField] = constants.UNSET,
context_id_field: ContextUUIDField = constants.UNSET,
related_name: Union[str, None] = None,
model_name: Union[str, None] = None,
app_label: Union[str, None] = None,
base_model: Type[models.Model] = None,
attrs: Dict[str, Any] = None,
meta: Dict[str, Any] = None
)
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:
Name | Type | Description | Default |
---|---|---|---|
*trackers |
Tracker
|
The event trackers. When using any tracker that inherits pghistory.DatabaseTracker, such as pghistory.AfterInsert, a Postgres trigger will be installed that automatically tracks the event with a generated event model. Trackers that do not inherit pghistory.DatabaseTracker are assumed to have manual events created by the user. |
()
|
fields |
Union[List[str], 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 |
None
|
exclude |
Union[List[str], None]
|
Instead of providing a list of fields to snapshot, a user can instead provide a list of fields to not snapshot. |
None
|
obj_fk |
ObjForeignKey
|
The old (and deprecated) object field. |
UNSET
|
context_fk |
Union[ContextForeignKey, ContextJSONField]
|
The old (and deprecated) context field. |
UNSET
|
obj_field |
ObjForeignKey
|
The foreign key field configuration that references the tracked object.
Defaults to an unconstrained non-nullable foreign key. Use |
UNSET
|
context_field |
Union[ContextForeignKey, ContextJSONField]
|
The context field configuration. Defaults to a nullable unconstrained
foreign key. Use |
UNSET
|
context_id_field |
ContextUUIDField
|
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 |
UNSET
|
related_name |
Union[str, None]
|
The old (and deprecated) related name field. |
None
|
model_name |
Union[str, 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. |
None
|
app_label |
Union[str, 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. |
None
|
base_model |
Type[Model]
|
The base model for the event model. Must inherit |
None
|
attrs |
Dict[str, Any]
|
Additional attributes to add to the event model |
None
|
meta |
Dict[str, Any]
|
Additional attributes to add to the Meta class of the event model. |
None
|
Source code in pghistory/core.py
670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 |
|
pghistory.admin
pghistory.admin.EventModelAdmin
Bases: BaseEventAdmin
The base admin for event models
pghistory.admin.EventsAdmin
Bases: BaseEventAdmin
The admin for showing events across all event models
pghistory.middleware
pghistory.middleware.WSGIRequest
Bases: WSGIRequest
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.middleware.HistoryMiddleware
Annotates the user/url in the pghistory context.
Source code in pghistory/middleware.py
pghistory.models
pghistory.models.AggregateEvent
Bases: BaseAggregateEvent
A proxy model for aggregating events together across tables and rendering diffs
pghistory.models.BaseAggregateEvent
pghistory.models.Context
Bases: Model
install_pgh_attach_context_func
classmethod
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.
Source code in pghistory/models.py
pghistory.models.Event
Bases: Model
An abstract model for base elements of a event
check
classmethod
Allow proxy models to inherit this model and define their own fields that are dynamically pulled from context
Source code in pghistory/models.py
pghistory_setup
classmethod
Called when the class is prepared (see apps.py) to finalize setup of the model and register triggers
Source code in pghistory/models.py
revert
Reverts the tracked model based on the event fields.
Raises a RuntimeError if the event model doesn't track all fields
Source code in pghistory/models.py
pghistory.models.EventQuery
Bases: Query
A query over an event CTE when proxy fields are used
get_compiler
Overrides the Query method get_compiler in order to return an EventQueryCompiler.
Source code in pghistory/models.py
pghistory.models.EventQueryCompiler
Bases: SQLCompiler
as_sql
If there are proxied fields on the event model, return a select from a CTE. Otherwise don't do anything special
Source code in pghistory/models.py
pghistory.models.EventQuerySet
pghistory.models.Events
Bases: Model
A proxy model for aggregating events together across tables and rendering diffs
check
classmethod
Allow proxy models to inherit this model and define their own fields that are dynamically pulled from context
Source code in pghistory/models.py
pghistory.models.EventsQuery
pghistory.models.EventsQueryCompiler
Bases: SQLCompiler
pghistory.models.EventsQuerySet
Bases: QuerySet
QuerySet with support for Common Table Expressions
Source code in pghistory/models.py
across
Aggregates events across the provided event models
references
Query any rows that reference the objs.
If, for example, a foreign key or pgh_obj field points to the object, it will be aggregated.
Source code in pghistory/models.py
tracks
Query any rows with pgh_obj equal to the objs.
Source code in pghistory/models.py
pghistory.models.MiddlewareEvents
Bases: Events
A proxy model for aggregating events. Includes additional fields that are captured by the pghistory middleware
pghistory.models.NoObjectsManager
Bases: Manager
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
pghistory.models.PghEventModel
A descriptor for accessing the pgh_event_model field on a tracked model