### Setup Development Environment Source: https://django-pghistory.readthedocs.io/en/3.8.0/contributing Instructions for setting up the django-pghistory development environment. It provides commands for cloning the repository, navigating into the directory, and setting up a Docker-managed environment. An alternative Conda setup is also mentioned. ```bash git clone git@github.com:AmbitionEng/django-pghistory.git cd django-pghistory make docker-setup ``` -------------------------------- ### Install django-pghistory Source: https://django-pghistory.readthedocs.io/en/3.8.0/installation Installs the django-pghistory library using pip. After installation, you need to add 'pghistory' and 'pgtrigger' to your Django project's INSTALLED_APPS. ```bash pip3 install django-pghistory ``` -------------------------------- ### Django-pghistory: Documentation Updates Source: https://django-pghistory.readthedocs.io/en/3.8.0/release_notes Includes various documentation improvements such as cleaning up the configuration section, documenting all settings, modifying conditional tracking examples, adding an FAQ on backfilling data, adjusting the guide on tracking management commands, and noting Q/A discussions in the FAQ. ```Python # No specific code snippet provided, but refers to comprehensive documentation updates. ``` -------------------------------- ### setup Method Source: https://django-pghistory.readthedocs.io/en/3.8.0/module A placeholder method to set up the tracker for the event model. By default, it does nothing. ```Python setup(event_model) ``` ```Python def setup(self, event_model): """Set up the tracker for the event model""" pass ``` -------------------------------- ### Django-pghistory: Conditional Tracking Examples Source: https://django-pghistory.readthedocs.io/en/3.8.0/release_notes Updates examples related to conditional history tracking, likely demonstrating how to configure and use this feature. ```Python # No specific code snippet provided, but refers to updated examples. ``` -------------------------------- ### Build and Serve Documentation Source: https://django-pghistory.readthedocs.io/en/3.8.0/contributing Instructions for building and serving the documentation for django-pghistory using Mkdocs Material. Provides commands to build the documentation and a shortcut to serve it locally. ```bash make docs ``` ```bash make docs-serve ``` -------------------------------- ### Django-pghistory Event Model Setup Source: https://django-pghistory.readthedocs.io/en/3.8.0/module Finalizes the setup of the Event model and registers triggers. It configures tracked models to associate event models and sets up utility properties for event model management. ```python from django.db.models import Model from pghistory.models import PghEventModel class Event(Model): # ... other model definitions ... @classmethod def pghistory_setup(cls): """ Called when the class is prepared (see apps.py) to finalize setup of the model and register triggers """ if ( not cls._meta.abstract and cls._meta.managed and not cls._meta.proxy ): # pragma: no branch for tracker in cls.pgh_trackers or []: tracker.pghistory_setup(cls) # Set up the event model utility properties. Don't overwrite any # existing attributes if not hasattr(cls.pgh_tracked_model, "pgh_event_models"): cls.pgh_tracked_model.pgh_event_models = {} # Use dir here, otherwise the property is evaluated if "pgh_event_model" not in dir(cls.pgh_tracked_model): cls.pgh_tracked_model.pgh_event_model = PghEventModel() if isinstance(cls.pgh_tracked_model.pgh_event_models, dict): # pragma: no branch cls.pgh_tracked_model.pgh_event_models.update( {tracker.label: cls for tracker in cls.pgh_trackers or []} ) ``` -------------------------------- ### Verifying Trigger Installation and Functionality Source: https://django-pghistory.readthedocs.io/en/3.8.0/faq Provides methods to confirm that triggers are correctly installed and operational. This includes writing automated tests, using the `pgtrigger ls` management command, and checking for migration issues with `manage.py check`. ```Python python manage.py pgtrigger ls ``` ```Python python manage.py check ``` -------------------------------- ### Troubleshooting Trigger Issues Source: https://django-pghistory.readthedocs.io/en/3.8.0/troubleshooting If you encounter issues with triggers installed by django-pghistory, consult django-pgtrigger's troubleshooting guide for common problems related to trigger creation and migration. ```python If you have issues with the triggers that are installed by `django-pghistory`, we recommend reading django-pgtrigger's troubleshooting guide. It goes over most of the core issues that might happen when creating or migrating triggers. ``` -------------------------------- ### pghistory_setup Method Source: https://django-pghistory.readthedocs.io/en/3.8.0/module Registers the tracker for the event model and calls user-defined setup. It ensures that a tracker with the same label is not already registered for a different event model. ```Python pghistory_setup(event_model) ``` ```Python def pghistory_setup(self, event_model): """Registers the tracker for the event model and calls user-defined setup""" tracked_model = event_model.pgh_tracked_model if _registered_trackers.get((tracked_model, self.label), event_model) != event_model: raise ValueError( f'Tracker with label "{self.label}" already exists for a different' f' event model of "{tracked_model._meta.label}". Supply a' " different label as the first argument to the tracker." ) _registered_trackers[(tracked_model, self.label)] = event_model self.setup(event_model) ``` -------------------------------- ### Install Context Function in Test Suite Source: https://django-pghistory.readthedocs.io/en/3.8.0/faq Provides a solution for the `_pgh_attach_context() does not exist` error in test suites. This error occurs when migrations are not run. Setting `PGHISTORY_INSTALL_CONTEXT_FUNC_ON_MIGRATE=True` in test settings ensures the context tracking function is installed. ```Python # settings.py (for tests) # PGHISTORY_INSTALL_CONTEXT_FUNC_ON_MIGRATE = True ``` -------------------------------- ### Django-pghistory: Performance and Scaling Guide Source: https://django-pghistory.readthedocs.io/en/3.8.0/release_notes Includes a usage guide in the "Performance and Scaling" section of the documentation, detailing how statement-level triggers work with conditional history tracking and any associated caveats. ```Python # No specific code snippet provided, but refers to documentation content. ``` -------------------------------- ### Run Tests and Linting Source: https://django-pghistory.readthedocs.io/en/3.8.0/contributing Commands for running tests and validating code quality for django-pghistory. Includes running tests on a single Python version, the full test suite across all supported versions, linting the code, and fixing common linting errors. ```bash make test ``` ```bash make full-test-suite ``` ```bash make lint ``` ```bash make lint-fix ``` -------------------------------- ### Fix Documentation Example for Tracking Events Source: https://django-pghistory.readthedocs.io/en/3.8.0/release_notes Corrects a bug found in the documentation's example for tracking events. ```Text # Fix documentation example for tracking events. ``` -------------------------------- ### Install Context Tracking Function in Migration Source: https://django-pghistory.readthedocs.io/en/3.8.0/release_notes The Postgres pghistory function is now installed within a migration. This resolves issues that previously occurred when attempting to migrate pghistory triggers. ```Python # In your Django migration file: from django.db import migrations def install_pghistory_function(apps, schema_editor): # SQL to install the function pass class Migration(migrations.Migration): dependencies = [('your_app', '000x_previous_migration')] operations = [ migrations.RunPython(install_pghistory_function), ] ``` -------------------------------- ### Middleware Support for GET and DELETE Requests Source: https://django-pghistory.readthedocs.io/en/3.8.0/release_notes The django-pghistory middleware now adds context for GET and DELETE requests, in addition to the previously supported POST, PUT, and PATCH requests. ```Python # Middleware automatically tracks GET, POST, PUT, PATCH, DELETE ``` -------------------------------- ### Middleware and Context Tracking Settings Source: https://django-pghistory.readthedocs.io/en/3.8.0/settings Configures how django-pghistory's middleware tracks HTTP methods and serializes context data. It also controls the installation of context tracking functions during migrations. ```APIDOC PGHISTORY_MIDDLEWARE_METHODS: Description: Set the HTTP methods tracked by the middleware. Default: ("GET", "POST", "PUT", "PATCH", "DELETE") PGHISTORY_JSON_ENCODER: Description: The JSON encoder class or class path to use when serializing context. Default: "django.core.serializers.json.DjangoJSONEncoder" PGHISTORY_INSTALL_CONTEXT_FUNC_ON_MIGRATE: Description: Install the Postgres `_pgh_attach_context` function after migrations. Ensures pghistory context tracking works even without running migrations, typically for test suites. Default: False ``` -------------------------------- ### Example Django Models for Referencing Events Source: https://django-pghistory.readthedocs.io/en/3.8.0/aggregating_events Provides example Django models (`Company` and `Product`) to illustrate how foreign key relationships can be used with pghistory's `objects.references()` method to track events related to objects. ```Python from django.db import models class Company(models.Model): name = models.TextField() class Product(models.Model): company = models.ForeignKey(Company, on_delete=models.CASCADE) ``` -------------------------------- ### Example Usage of Tracked Model Events Source: https://django-pghistory.readthedocs.io/en/3.8.0/event_tracking Provides an example of creating and updating a tracked model, then accessing and printing the generated event data, including object ID, label, and tracked field values. ```Python from myapp.models import TrackedModel m = TrackedModel.objects.create(int_field=1, text_field="hello") m.int_field = 2 m.save() # "events" is the default related name of the event model. print(m.events.values("pgh_obj", "pgh_label", "int_field")) # Expected Output: # [ # {'pgh_obj': 1, 'pgh_label': 'insert', 'int_field': 1}, # {'pgh_obj': 1, 'pgh_label': 'update', 'int_field': 2} # ] ``` -------------------------------- ### Django-pghistory: Configuration Settings Source: https://django-pghistory.readthedocs.io/en/3.8.0/release_notes Introduces new settings for configuring history tracking behavior. `PGHISTORY_INSTALL_CONTEXT_FUNC_ON_MIGRATE` controls the installation of the tracking function after migrations, and `PGHISTORY_CREATED_AT_FUNCTION` allows specifying the function for determining the current time in history triggers. ```Python # In settings.py: # PGHISTORY_INSTALL_CONTEXT_FUNC_ON_MIGRATE = True # PGHISTORY_CREATED_AT_FUNCTION = 'my_custom_time_function' ``` -------------------------------- ### Install pgh_attach_context_func Stored Procedure Source: https://django-pghistory.readthedocs.io/en/3.8.0/module Installs a custom stored procedure for upserting context for historical events. This procedure is automatically installed in pghistory migration 0004 and is aware of when tracking is enabled via pghistory.context(). ```python import uuid from django.db import connections from django.db.models import Model from django.db.utils import DEFAULT_DB_ALIAS class Event(Model): # ... other model definitions ... @classmethod def install_pgh_attach_context_func(cls, using: str = DEFAULT_DB_ALIAS) -> None: """ 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. """ connection = connections[using] if not connection.vendor.startswith("postgres"): # pragma: no cover return with connection.cursor() as cursor: cursor.execute( f""" CREATE OR REPLACE FUNCTION _pgh_attach_context() RETURNS {cls._meta.db_table}.id%TYPE AS $$ DECLARE _pgh_context_id UUID; _pgh_context_metadata JSONB; BEGIN BEGIN SELECT INTO _pgh_context_id CURRENT_SETTING('pghistory.context_id'); SELECT INTO _pgh_context_metadata CURRENT_SETTING('pghistory.context_metadata'); EXCEPTION WHEN OTHERS THEN END; IF _pgh_context_id IS NOT NULL AND _pgh_context_metadata IS NOT NULL THEN INSERT INTO {cls._meta.db_table} (id, metadata, created_at, updated_at) VALUES (_pgh_context_id, _pgh_context_metadata, NOW(), NOW()) ON CONFLICT (id) DO UPDATE SET metadata = EXCLUDED.metadata, updated_at = EXCLUDED.updated_at WHERE {cls._meta.db_table}.metadata != EXCLUDED.metadata; RETURN _pgh_context_id; ELSE RETURN NULL; END IF; END; $$ LANGUAGE plpgsql;""" ) ``` -------------------------------- ### Configure Middleware Tracked Methods Source: https://django-pghistory.readthedocs.io/en/3.8.0/release_notes Allows configuration of which HTTP methods are tracked by the django-pghistory middleware. Defaults to ('GET', 'POST', 'PUT', 'PATCH', 'DELETE'). ```Python settings.PGHISTORY_MIDDLEWARE_METHODS = ("GET", "POST", "PUT", "PATCH", "DELETE") ``` -------------------------------- ### Example Event Data Structure Source: https://django-pghistory.readthedocs.io/en/3.8.0/aggregating_events Provides an example of the data structure for events tracked by django-pghistory. It includes fields like `pgh_slug`, `pgh_model`, `pgh_data` (raw data), and `pgh_diff` (changes between events). ```APIDOC { "pgh_slug": "app.UserEvent:" "pgh_model": "app.UserEvent", "pgh_id": "", "pgh_created_at": datetime(2020, 6, 17, 12, 20, 10), "pgh_label": "snapshot", "pgh_data": { "username": "hello", "name": "world", "id": "" }, "pgh_diff": None, "pgh_context_id": None, "pgh_context": None, "pgh_obj_model": "app.User", "pgh_obj_id": "" }, { "pgh_slug": "app.UserEvent:", "pgh_model": "app.UserEvent", "pgh_id": "", "pgh_created_at": datetime(2020, 6, 17, 12, 20, 20), "pgh_label": "snapshot", "pgh_data": { "username": "hi", "name": "world", "id": "" }, "pgh_diff": { "username": ["hello", "hi"] }, "pgh_context_id": None, "pgh_context": None, "pgh_obj_model": "app.User", "pgh_obj_id": "" } ``` -------------------------------- ### Custom HistoryMiddleware with IP Address Source: https://django-pghistory.readthedocs.io/en/3.8.0/context Provides an example of extending `pghistory.middleware.HistoryMiddleware` to include the request's IP address in the context metadata. ```Python import pghistory.middleware class HistoryMiddleware(pghistory.middleware.HistoryMiddleware): def get_context(self, request): return super().get_context(request) | { "ip_address": request.META.get('REMOTE_ADDR', 'unknown'), } ``` -------------------------------- ### Django Admin Integration Installation Source: https://django-pghistory.readthedocs.io/en/3.8.0/admin Activate the django-pghistory admin integration by adding 'pghistory.admin' to your Django project's INSTALLED_APPS. It's crucial to place it above 'django.contrib.admin' to ensure custom admin templates are correctly applied. ```Python settings.py: INSTALLED_APPS = [ ... "pghistory.admin", "django.contrib.admin", ... ] ``` -------------------------------- ### Track Models with Concrete Inheritance Source: https://django-pghistory.readthedocs.io/en/3.8.0/faq Demonstrates how to track models with concrete inheritance in Django using django-pghistory. It highlights the need to set proper reverse foreign key names to avoid clashes and provides an example of how to configure this using `related_name` and `related_query_name`. ```Python @pghistory.track() class Parent(models.Model): field_a = models.CharField(default="unknown") @pghistory.track() class Child(Parent): field_b = models.CharField(default="unknown") ``` ```Python @pghistory.track( obj_field=pghistory.ObjForeignKey( related_name="parent_event", related_query_name="parent_event_query", ) ) class Parent(models.Model): field_a = models.CharField(default="unknown") @pghistory.track( obj_field=pghistory.ObjForeignKey( related_name="child_event", related_query_name="child_event_query", ) ) class Child(Parent): field_b = models.CharField(default="unknown") ``` -------------------------------- ### Django pghistory: Manual Event Creation Source: https://django-pghistory.readthedocs.io/en/3.8.0/event_tracking Shows how to manually create events using pghistory.create_event when automatic tracking is not sufficient. This example demonstrates registering a pghistory.ManualEvent tracker and then creating an event with a specific label after an object is created. ```Python import pghistory from django.db import models @pghistory.track( pghistory.ManualEvent("user_create"), fields=['username'] ) class MyUser(models.Model): username = models.CharField(max_length=64) password = models.PasswordField() # Create a user and manually create a "user.create" event user = MyUser.objects.create(...) pghistory.create_event(user, label="user_create") ``` -------------------------------- ### Attaching Context to Pre-existing Session Source: https://django-pghistory.readthedocs.io/en/3.8.0/context Shows how to attach context to an existing session without starting a new one. If no session has been previously entered, the context will not be stored. ```Python import pghistory # Assuming a context session has already been started pghistory.context(key="value") ``` -------------------------------- ### Query Events using EventsProxy with Proxied Fields Source: https://django-pghistory.readthedocs.io/en/3.8.0/aggregating_events Demonstrates querying events using an `EventsProxy` model that has proxied context fields. This example filters events by a specific URL stored in the context metadata. ```Python EventsProxy.objects.tracks(object).filter(url="https://some_url.com") ``` -------------------------------- ### Track User Model Changes Source: https://django-pghistory.readthedocs.io/en/3.8.0/upgrading Example of tracking changes to Django's user model using `pghistory.track`, excluding the password field. This demonstrates how to register trackers on proxy models for third-party models. ```Python from django.contrib.auth.models import User import pghistory # Track the user model, excluding the password field @pghistory.track( pghistory.Snapshot("user.snapshot"), exclude=["password"], ) class UserProxy(User): class Meta: proxy = True ``` -------------------------------- ### Example Usage: Conditional Email Update Tracking Source: https://django-pghistory.readthedocs.io/en/3.8.0/event_tracking Demonstrates the behavior of the conditional email update tracking setup. It shows that events are only created when the email field is modified, not when other fields like address are changed. ```Python from myapp.models import MyUser, UserEmailHistory u = MyUser.objects.create( username="hello", email="hello@hello.com", address="123 Main St" ) # Events are only tracked on updates, so nothing has been stored yet assert not UserEmailHistory.objects.exists() # Change the address. An event is not created u.address = "456 Main St" u.save() assert not UserEmailHistory.objects.exists() # Change the email. An event should be stored u.email = "world@world.com" u.save() print(UserEmailHistory.objects.filter(pgh_obj=u).values_list("email", flat=True)) > ["hello@hello.com"] ``` -------------------------------- ### Django-pghistory: Backfilling Data FAQ Source: https://django-pghistory.readthedocs.io/en/3.8.0/release_notes Adds a section to the Frequently Asked Questions (FAQ) addressing how to backfill data with Django-pghistory. ```Python # No specific code snippet provided, but refers to FAQ content. ``` -------------------------------- ### Simplified django-pghistory Tracking Source: https://django-pghistory.readthedocs.io/en/3.8.0/upgrading Demonstrates the simplified usage of `pghistory.track()` without arguments, leveraging default trackers. This is the recommended approach for users who previously used `pghistory.Snapshot()`. ```python pghistory.track(pghistory.Snapshot()) # Old usage pghistory.track() # New, simplified usage ``` -------------------------------- ### FAQ for Concrete Inheritance Issues Source: https://django-pghistory.readthedocs.io/en/3.8.0/release_notes Adds a section to the FAQ addressing common issues encountered when dealing with concrete inheritance. ```Markdown ## Added section in FAQ for handling issues with concrete inheritance ``` -------------------------------- ### Django-pghistory: ASGI Support Source: https://django-pghistory.readthedocs.io/en/3.8.0/release_notes Adds support for Asynchronous Server Gateway Interface (ASGI) applications, enabling Django-pghistory to function within ASGI environments. ```Python # No specific code snippet provided, but indicates ASGI compatibility. ``` -------------------------------- ### Context Tracking with Middleware Source: https://django-pghistory.readthedocs.io/en/3.8.0/faq Explains how to associate the logged-in user and request URL with historical events by enabling `django-pghistory`'s context tracking middleware. ```Python MIDDLEWARE = [ # ... 'pghistory.middleware.ContextTrackingMiddleware', # ... ] ``` -------------------------------- ### Django-pghistory: Tracking Management Commands Source: https://django-pghistory.readthedocs.io/en/3.8.0/release_notes Provides guidance on tracking management commands within Django-pghistory. ```Python # No specific code snippet provided, but refers to documentation on tracking management commands. ``` -------------------------------- ### Django-pghistory: Denormalized Context Usage Source: https://django-pghistory.readthedocs.io/en/3.8.0/release_notes Ensures that `pghistory.create_event` functions correctly when using denormalized context, and provides documentation on migrating existing tracking models to denormalized context. ```Python # No specific code snippet provided, but refers to correct functioning with denormalized context. ``` -------------------------------- ### Context Tracking Function on Non-Postgres Databases Source: https://django-pghistory.readthedocs.io/en/3.8.0/release_notes Prevents pghistory's context tracking function from being installed on non-Postgres databases. ```Python # Don't install pghistory's context tracking function on non-postgres databases ``` -------------------------------- ### Django Pghistory Trivial Updates Source: https://django-pghistory.readthedocs.io/en/3.8.0/release_notes Lists trivial updates and refactors in django-pghistory, including replacing `SET LOCAL` with `SELECT set_config`, updating Django templates, and renaming modules. ```Python # Replace usage of SET LOCAL with SELECT set_config for better pg stat reporting. # Fix make lint command with new .gitignore changes # Updated with latest django template # Rename "tracking" module to "runtime" module. ``` -------------------------------- ### EventsQuery Initialization Source: https://django-pghistory.readthedocs.io/en/3.8.0/module Initializes an EventsQuery, which is a query over an aggregate event CTE. It sets up internal lists for references, tracks, and across clauses. ```Python def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.references = [] self.tracks = [] self.across = [] ``` -------------------------------- ### Django-pghistory: Async Support for Context Source: https://django-pghistory.readthedocs.io/en/3.8.0/release_notes Adds asynchronous support for `pghistory.context`, allowing context tracking to be used in asynchronous Django views or operations. ```Python # No specific code snippet provided, but indicates async compatibility for context. ``` -------------------------------- ### Track Changes to Specific Field (User) Source: https://django-pghistory.readthedocs.io/en/3.8.0/event_tracking Example showing how to explicitly track changes to the 'user' field using a condition, even if it's not included in the default tracked fields. ```Python pghistory.AnyChange("user") ``` -------------------------------- ### EventQuerySet Initialization Source: https://django-pghistory.readthedocs.io/en/3.8.0/module Initializes an EventQuerySet, which provides support for proxy fields. If no query is provided, it defaults to an EventQuery. ```Python def __init__(self, model=None, query=None, using=None, hints=None): if query is None: query = EventQuery(model) super().__init__(model, query, using, hints) ``` -------------------------------- ### Django-pghistory: Project Ownership Change Source: https://django-pghistory.readthedocs.io/en/3.8.0/release_notes Announces a change in project ownership to `AmbitionEng`. ```Python # No specific code snippet provided, but indicates a change in project maintainership. ``` -------------------------------- ### Track User Group Add/Remove Events Source: https://django-pghistory.readthedocs.io/en/3.8.0/upgrading Example of tracking add and remove events for user groups on the Django user model. This uses `pghistory.track` with `AfterInsert` and `BeforeDelete` to capture group membership changes. ```Python from django.contrib.auth.models import User import pghistory # Track add and remove events to user groups @pghistory.track( pghistory.AfterInsert("group.add"), pghistory.BeforeDelete("group.remove"), obj_fk=None, ) class UserGroups(User.groups.through): class Meta: proxy = True ``` -------------------------------- ### Deprecations in pghistory.track Source: https://django-pghistory.readthedocs.io/en/3.8.0/upgrading Details the deprecated arguments for `pghistory.track` in version 2.5, including `obj_fk`, `context_fk`, and `related_name`, and explains the preferred new arguments and configurations. ```APIDOC pghistory.track: - obj_fk: Deprecated in favor of obj_field. The new argument must be supplied a pghistory.ObjForeignKey instance. - context_fk: Deprecated in favor of context_field. The new argument must be a pghistory.ContextForeignKey. If denormalizing context, it must be a pghistory.ContextJSONField argument. - related_name: Deprecated. Supply the related_name argument to the instance of the obj_field argument. For example, obj_field=pghistory.ObjForeignKey(related_name="events"). ``` -------------------------------- ### PGHISTORY_EXCLUDE_FIELD_KWARGS Source: https://django-pghistory.readthedocs.io/en/3.8.0/settings Ignores specific keyword arguments passed to Django model fields to prevent conflicts. It's a dictionary mapping field classes or paths to lists of arguments to ignore. For example, `{models.ImageField: ['primary_key']}`. ```python PGHISTORY_EXCLUDE_FIELD_KWARGS = { models.ImageField: ["primary_key"] } ``` -------------------------------- ### Remove Dependency on django-pgconnection Source: https://django-pghistory.readthedocs.io/en/3.8.0/release_notes django-pghistory no longer requires users to wrap `settings.DATABASES` with `django-pgconnection`. ```Python # No longer need to configure DATABASES like this: # DATABASES = { # 'default': pgconnection.settings(... # )} ``` -------------------------------- ### Django-pghistory: Event and DatabaseEvent Renaming Source: https://django-pghistory.readthedocs.io/en/3.8.0/upgrading The pghistory.Event class has been renamed to pghistory.Tracker, and pghistory.DatabaseEvent has been renamed to pghistory.DatabaseTracker. ```APIDOC pghistory.Event * Deprecated and renamed to `pghistory.Tracker`. ``` ```APIDOC pghistory.DatabaseEvent * Deprecated and renamed to `pghistory.DatabaseTracker`. ``` -------------------------------- ### Django pghistory: Multiple Trackers for Different Schemas Source: https://django-pghistory.readthedocs.io/en/3.8.0/event_tracking Illustrates how to use multiple pghistory.track decorators on a single model to track different events with distinct schemas. This example shows tracking email changes and username changes separately, each with its own history model. ```Python import pghistory from django.db import models @pghistory.track( pghistory.UpdateEvent( "email_changed", row=pghistory.Old, condition=pghistory.AnyChange("email") ), fields=["email"], model_name="UserEmailHistory" ) @pghistory.track( pghistory.UpdateEvent( "username_changed", row=pghistory.Old, condition=pghistory.AnyChange("username") ), fields=["username"], model_name="UserUsernameHistory" ) class TrackedModel(models.Model): ... ``` -------------------------------- ### Handling Bytes Representations of SQL Source: https://django-pghistory.readthedocs.io/en/3.8.0/release_notes Ensures that `bytes` representations of SQL are handled correctly. ```Python # Ensure `bytes` representations of SQL are handled ``` -------------------------------- ### Django-pghistory API Reference Source: https://django-pghistory.readthedocs.io/en/3.8.0/release_notes This section details the API for django-pghistory, including settings and core functionalities. It serves as a reference for developers integrating or extending the library. ```APIDOC Settings: PGHISTORY_ENABLE_GLOBAL_TABLES: bool Enables or disables global tables for all models. Default: True PGHISTORY_ENABLE_GLOBAL_TABLES_FOR_MODELS: list[str] A list of model strings (app_label.ModelName) to enable global tables for. If empty, all models are considered. Default: [] PGHISTORY_ENABLE_GLOBAL_TABLES_EXCLUDE_MODELS: list[str] A list of model strings (app_label.ModelName) to exclude from global tables. Default: [] PGHISTORY_ENABLE_GLOBAL_TABLES_EXCLUDE_APPS: list[str] A list of app labels to exclude from global tables. Default: [] PGHISTORY_ENABLE_GLOBAL_TABLES_EXCLUDE_TABLES: list[str] A list of table names to exclude from global tables. Default: [] Reference: pghistory.snapshot(obj, *, fields=None, exclude=None, use_pk=False) Creates a snapshot of a model instance. Parameters: obj: The model instance to snapshot. fields: A list of fields to include in the snapshot. exclude: A list of fields to exclude from the snapshot. use_pk: Whether to include the primary key in the snapshot. Returns: A dictionary representing the snapshot. pghistory.track(obj, *, fields=None, exclude=None, use_pk=False) Tracks changes to a model instance. Parameters: obj: The model instance to track. fields: A list of fields to track. exclude: A list of fields to exclude from tracking. use_pk: Whether to include the primary key in tracking. Returns: None pghistory.get_history(obj) Retrieves the history of a model instance. Parameters: obj: The model instance. Returns: A QuerySet of history objects. pghistory.get_diff(obj1, obj2) Calculates the difference between two model instances. Parameters: obj1: The first model instance. obj2: The second model instance. Returns: A dictionary representing the differences. ``` -------------------------------- ### Track Model Events Decorator Source: https://django-pghistory.readthedocs.io/en/3.8.0/module Dynamically generates an event model to snapshot model changes based on supplied trackers and fields. It can automatically install Postgres triggers or require manual event creation. Configuration options include fields to snapshot, exclude, context fields, and model naming. ```python def track_fields(*trackers, fields=None, exclude=None, obj_field=None, context_field=None, context_id_field=None, append_only=False, model_name=None, app_label=None, base_model=None, attrs=None, meta=None, level=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. Args: *trackers: The event trackers. When using any tracker that inherits [pghistory.RowEvent][], such as [pghistory.InsertEvent][], a Postgres trigger will be installed that automatically stores the event into the generated event model. Trackers that do not inherit [pghistory.RowEvent][] must be manually created. If no events are supplied, defaults to `pghistory.InsertEvent` and `pghistory.UpdateEvent`. fields: 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 `DatabaseTracker` object. Manual events must specify these fields during manual creation. exclude: Instead of providing a list of fields to snapshot, a user can instead provide a list of fields to not snapshot. obj_field: 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: The context field configuration. Defaults to a nullable unconstrained foreign key. Use `None` to avoid attaching historical context altogether. context_id_field: 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. append_only: True if the event model is protected against updates and deletes. model_name: 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: 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: The base model for the event model. Must inherit `pghistory.models.Event`. attrs: Additional attributes to add to the event model meta: Additional attributes to add to the Meta class of the event model. level: The trigger level to use for tracking events. """ def _model_wrapper(model_class): create_event_model( model_class, *trackers, fields=fields, exclude=exclude, obj_field=obj_field, context_field=context_field, context_id_field=context_id_field, append_only=append_only, model_name=model_name, app_label=app_label, abstract=False, base_model=base_model, attrs=attrs, meta=meta, level=level, ) return model_class return _model_wrapper ``` -------------------------------- ### Backfill Events Source: https://django-pghistory.readthedocs.io/en/3.8.0/faq Explains how to backfill events for existing data in django-pghistory. This can be done using manual event tracking or by bulk creating events. For large backfills, it's recommended to import the model in a migration and reference `model.pgh_event_model`. ```Python # Example using manual event tracking # from myapp.models import MyModel # event = MyModel.pgh_event_model.objects.create(pgh_obj=my_model_instance, ...) # Example for bulk creation in migrations # from myapp.models import MyModel # events_to_create = [ # MyModel.pgh_event_model( # pgh_obj=instance, # # other fields... # ) # for instance in MyModel.objects.all() # ] # MyModel.pgh_event_model.objects.bulk_create(events_to_create) ``` -------------------------------- ### Django Pghistory Configuration and Features Source: https://django-pghistory.readthedocs.io/en/3.8.0/release_notes Details on configuring pghistory, including new event model configuration, proxy fields, and integration with Django admin. It also covers features like automatic 'pgh_event_model' attribute, optional 'label' argument, and simplified conditions for snapshots. ```Python settings.py: INSTALLED_APPS = [ ... 'pghistory.admin', ... ] # Example of using ProxyField for proxying relationships from pghistory import ProxyField class MyEventModel(Events): user = ProxyField(to='context.user') # Example of new event model configuration from pghistory import Field class MyTrackedModel(models.Model): obj_field = Field(attribute='my_object') context_field = Field(attribute='my_context') # Example of revert method usage # event_model.revert() ``` -------------------------------- ### pghistory.ManualEvent Initialization Source: https://django-pghistory.readthedocs.io/en/3.8.0/module Initializes a ManualEvent for manually tracking events. It requires a label to be provided. ```python def __init__(self, label=None): self.label = label or self.label if not self.label: # pragma: no cover raise ValueError("Must supply label attribute to event") ``` -------------------------------- ### Fix Default App Config Warning Source: https://django-pghistory.readthedocs.io/en/3.8.0/release_notes Addresses a warning related to `default_app_config` for Django versions 3.2 and later. ```Python # Configuration updated to avoid default_app_config warnings on newer Django versions. ``` -------------------------------- ### Configuring Default Trackers in django-pghistory Source: https://django-pghistory.readthedocs.io/en/3.8.0/upgrading Shows how to configure `PGHISTORY_DEFAULT_TRACKERS` in Django settings to retain the original 'snapshot' label behavior for insert and update events when using the new tracker classes. ```python PGHISTORY_DEFAULT_TRACKERS = ( pghistory.InsertEvent("snapshot"), pghistory.UpdateEvent("snapshot") ) ``` -------------------------------- ### Migrating django-pghistory Trackers Source: https://django-pghistory.readthedocs.io/en/3.8.0/upgrading Provides direct mappings for migrating from older pghistory tracker configurations to the new InsertEvent, UpdateEvent, and DeleteEvent classes. This helps users understand how to replicate previous tracking behaviors with the updated API. ```python pghistory.track(pghistory.AfterInsert()) == pghistory.track(pghistory.InsertEvent()) ``` ```python pghistory.track(pghistory.AfterInsertOrUpdate()) == pghistory.track(pghistory.InsertEvent(), pghistory.UpdateEvent(condition=None)) ``` ```python pghistory.track(pghistory.AfterUpdate()) == pghistory.track(pghistory.UpdateEvent(condition=None)) ``` ```python pghistory.track(pghistory.BeforeDelete()) == pghistory.track(pghistory.DeleteEvent) ``` ```python pghistory.track(pghistory.BeforeUpdate()) == pghistory.track(pghistory.UpdateEvent(row=pghistory.Old, condition=None)) ``` ```python pghistory.track(pghistory.BeforeUpdateOrDelete()) == pghistory.track(pghistory.UpdateEvent(row=pghistory.Old, condition=None), pghistory.DeleteEvent()) ``` -------------------------------- ### Django 5.0 Compatibility and Psycopg Support Source: https://django-pghistory.readthedocs.io/en/3.8.0/release_notes Adds compatibility and testing for Django 5.0, including support for both psycopg2 and psycopg3. ```Python # Django 5.0 compatibility # Support and test against Django 5 with psycopg2 and psycopg3. ``` -------------------------------- ### Basic Model Tracking with django-pghistory Source: https://django-pghistory.readthedocs.io/en/3.8.0/basics Demonstrates how to use the `@pghistory.track()` decorator to automatically track changes to a Django model. This generates an event model named `TrackedModelEvent` which stores historical versions of the `TrackedModel` data along with additional metadata fields. ```Python @pghistory.track() class TrackedModel(models.Model): int_field = models.IntegerField() text_field = models.TextField() ``` -------------------------------- ### Django pghistory: Q and F Conditions for Money Tracking Source: https://django-pghistory.readthedocs.io/en/3.8.0/event_tracking Demonstrates how to use pghistory.Q and pghistory.F constructs to create specific conditions for tracking monetary changes in a Django model. It shows how to log events when cash drops below a certain amount or when it increases or decreases. ```Python import pghistory from django.db import models @pghistory.track( pghistory.UpdateEvent( "money_below_one_hundred", condition=pghistory.Q(old__dollars__gte=100, new__dollars__lt=100) ), ) class Cash(models.Model): dollars = models.DecimalField() ``` ```Python import pghistory from django.db import models @pghistory.track( pghistory.UpdateEvent( "money_below_one_hundred", condition=pghistory.Q(old__dollars__gte=100, new__dollars__lt=100) ), pghistory.UpdateEvent( "money_down", condition=pghistory.Q(old__dollars__gt=pghistory.F("new__dollars")) ), pghistory.UpdateEvent( "money_up", condition=pghistory.Q(old__dollars__lt=pghistory.F("new__dollars")) ) ) class Cash(models.Model): dollars = models.DecimalField() ``` -------------------------------- ### Instrumenting Management Commands Source: https://django-pghistory.readthedocs.io/en/3.8.0/context Illustrates how to instrument `manage.py` to group events under a management command's context. It avoids tracking context for `runserver` and certain other commands like `migrate` and `test` to prevent disruptions. ```Python #!/usr/bin/env python import contextlib import os import sys import pghistory if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings") from django.core.management import execute_from_command_line if ( len(sys.argv) > 1 and not sys.argv[1].startswith("runserver") and sys.argv[1] not in ["migrate", "test"] ): # Group history context under the same management command if # we aren't running a server or running migration during migrate # or test command. history_context = pghistory.context(command=sys.argv[1]) else: history_context = contextlib.ExitStack() with history_context: execute_from_command_line(sys.argv) ``` -------------------------------- ### EventsQuerySet Initialization Source: https://django-pghistory.readthedocs.io/en/3.8.0/module Initializes an EventsQuerySet, which provides support for Common Table Expressions (CTEs). It defaults to an EventsQuery if no query is provided. ```Python def __init__(self, model=None, query=None, using=None, hints=None): # Only create an instance of a Query if this is the first invocation in # a query chain. if query is None: query = EventsQuery(model) super().__init__(model, query, using, hints) ``` -------------------------------- ### Django-pghistory: Deprecated Code Removal in v3 Source: https://django-pghistory.readthedocs.io/en/3.8.0/upgrading Details specific removals in v3, including `pghistory.Event`, `pghistory.DatabaseEvent`, `pghistory.get_event_model`, and arguments for `create_event_model` and `track`. ```APIDOC Deprecated code removed in v3: * `pghistory.Event` removed; use `pghistory.Tracker`. * `pghistory.DatabaseEvent` removed; use `pghistory.RowEvent`. * `pghistory.get_event_model` removed; use `pghistory.create_event_model`. * `obj_fk` argument removed; supply `pghistory.ObjForeignKey` to `obj_field`. * `context_fk` argument removed; supply `pghistory.ContextForeignKey` to `context_field`. * `related_name` argument removed; use `related_name` in `pghistory.ObjForeignKey`. * `name` argument for `create_event_model` removed; use `model_name`. ``` -------------------------------- ### Django 5.1 Compatibility and Dropped Support Source: https://django-pghistory.readthedocs.io/en/3.8.0/release_notes This update ensures compatibility with Django 5.1 and drops support for older versions, specifically Django 3.2 and Postgres 12. ```Python # Compatibility update for Django 5.1 # Dropped support for Django 3.2 / Postgres 12 ```