Install & Compatibility
Where this runs
tested against v3.9.2 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslpy 3.10–3.920 runs
installs and imports cleanly · install 0.0s · import 0.950s · 84.2MB
glibcpy 3.10–3.920 runs
installs and imports cleanly · install 4.1s · import 0.885s · 87MB
84MB installed
● package 84MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
context
✓ import pghistory
get_event_model
✓ import pghistory
ProxyField
✓ import pghistory.models
admin
✓ import pghistory.admin
✗ from django.contrib import admin; admin.site.register(MyHistoryModel)
pghistory provides its own admin integration for history models, which simplifies registration and adds extra features.
This quickstart demonstrates how to define a Django model and enable history tracking using the `@pghistory.track` decorator. It also shows how to retrieve the historical events through the automatically generated history model. Remember to add `pghistory` and `pghistory.admin` to `INSTALLED_APPS` and run `makemigrations` and `migrate` after defining your models.
import os
import django
from django.conf import settings
from django.db import models
settings.configure(
DEBUG=True,
INSTALLED_APPS=[
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
'pghistory',
'pghistory.admin',
'your_app_name' # Replace with your actual app name
],
DATABASES={
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': os.environ.get('PG_DB_NAME', 'test_db'),
'USER': os.environ.get('PG_DB_USER', 'test_user'),
'HOST': os.environ.get('PG_DB_HOST', 'localhost'),
'PORT': os.environ.get('PG_DB_PORT', '5432'),
'PASSWORD': os.environ.get('PG_DB_PASSWORD', 'password'),
}
},
MIDDLEWARE_CLASSES=(
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
),
TEMPLATES=[
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
],
STATIC_URL = '/static/',
SECRET_KEY = 'a-very-secret-key',
)
django.setup()
import pghistory
# Define your model
@pghistory.track(fields=['name', 'value'])
class MyModel(models.Model):
name = models.CharField(max_length=255)
value = models.IntegerField(default=0)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return f"{self.name} - {self.value}"
class Meta:
app_label = 'your_app_name'
# After running makemigrations and migrate:
# from your_app_name.models import MyModel
# obj = MyModel.objects.create(name='Test', value=10)
# obj.value = 20
# obj.save()
#
# HistoryModel = pghistory.get_event_model(MyModel)
# for event in HistoryModel.objects.all():
# print(f"ID: {event.pgh_obj_id}, Name: {event.name}, Value: {event.value}, Changed at: {event.pgh_created_at}")
Debug
Known issues
breakingPython 3.9 support was dropped in version 3.9.0. Ensure your project is running Python 3.10 or newer.fixUpgrade your Python environment to 3.10 or later. Consider Django 6.0 compatibility, which was also introduced in 3.9.0.
affects: >=3.9.0
gotchaInstalling `pghistory.admin` in `INSTALLED_APPS` registers the admin automatically for all tracked models. If you need custom admin registration for history models, you should not include `pghistory.admin` and register them manually using `pghistory.admin.site.register`.fixTo avoid automatic registration, remove 'pghistory.admin' from `INSTALLED_APPS` and register history models explicitly with `pghistory.admin.site.register(pghistory.get_event_model(MyModel))`.
affects: >=3.9.2 (documentation warning added), all versions.
gotchaContext tracking in `django-pghistory` can be ignored for certain SQL statements (e.g., `VACUUM`, `SELECT` without `FOR UPDATE`). This is by design to prevent issues or track irrelevant changes, but it means certain database operations will not generate context events.fixBe aware that context events are primarily for DML (INSERT, UPDATE, DELETE) operations. Do not expect context for all SQL statement types. Review the documentation for specific ignored statements.
affects: >=3.7.0, >=3.8.3
gotchaUpgrading existing tracking models to denormalized context requires specific migration steps. Simply changing tracking configuration won't automatically update existing history tables.fixRefer to the 'Migrating existing tracking models to denormalized context' section in the official documentation for detailed steps on how to migrate your historical data and schema.
affects: >=3.8.0
gotchaStatement-level history tracking (introduced in 3.6.0) significantly changes how triggers work, especially for bulk operations. While it offers performance improvements, it may alter the granularity or content of recorded history events compared to row-level tracking.fixIf adopting statement-level tracking (`@pghistory.track(level=pghistory.Statement)` or `PGHISTORY_LEVEL = pghistory.Statement`), thoroughly test how your history is recorded for bulk actions. Understand the differences in how `new`, `old`, and context data are captured.
affects: >=3.6.0
Upgrade
Version history
3.9.2latest on PyPI · released Feb 17, 2026
Audit
Dependencies
DjangorequiredCore framework dependency for the library.
psycopgrequiredPostgreSQL adapter for Django, required for interaction with the database triggers.