django-pgtrigger helps you write
for your Django models.
Why should I use triggers?¶
Triggers can solve a variety of complex problems more reliably, performantly, and succinctly than application code. For example,
Protecting operations on rows or columns (
Making read-only models or fields (
Soft-deleting models (
Snapshotting and tracking model changes (django-pghistory).
Enforcing field transitions (
Keeping a search vector updated for full-text search (
Building official interfaces (e.g. enforcing use of
Versioning models, mirroring fields, computing unique model hashes, and the list goes on…
All of these examples require no overridden methods, no base models, and no signal handling.
pip3 install django-pgtrigger and
pgtrigger.Trigger objects are added to
triggers in model
django-pgtrigger comes with several trigger classes,
pgtrigger.Protect. In the following, we’re protecting
the model from being deleted:
class ProtectedModel(models.Model): """This model cannot be deleted!""" class Meta: triggers = [ pgtrigger.Protect(name='protect_deletes', operation=pgtrigger.Delete) ]
When migrations are created and executed,
ProtectedModel will raise an
exception anytime a deletion is attempted.
Let’s extend this example further and only protect deletions on inactive objects.
In this example, the trigger conditionally runs when the row being deleted
OLD row in trigger terminology) is still active:
class ProtectedModel(models.Model): """Active object cannot be deleted!""" is_active = models.BooleanField(default=True) class Meta: triggers = [ pgtrigger.Protect( name='protect_deletes', operation=pgtrigger.Delete, condition=pgtrigger.Q(old__is_active=True) ) ]
pgtrigger.F objects to
conditionally execute triggers based on the
Combining these Django idioms with
can solve a wide variety of problems without ever writing SQL. Users,
however, can still use raw SQL for complex cases.
Triggers are installed like other database objects. Run
python manage.py makemigrations and
python manage.py migrate to install triggers.
django-pgtrigger is compatible with Python 3.7 – 3.10, Django 2.2 – 4.1, and Postgres 10 – 14.
We recommend everyone first read:
After this, there are several usage guides:
Trigger Cookbook for trigger examples.
Ignoring Execution for dynamically ignoring triggers.
Deferrable Triggers for deferring trigger execution.
Advanced Installation for installing triggers on third-party models, many-to-many models, programmatic installation, and more.
Advanced Database Setups for notes on how triggers work in multi-database, mutli-schema, or partitioned database setups.
There’s additional help in these sections:
Frequently Asked Questions for common questions like testing and disabling triggers.
Troubleshooting for advice on known issues.
Upgrading for upgrading to new major versions.
Talks and Tutorials for additional reading and videos.
Finally, core API information exists in these sections: