Package: django-pgtrigger
django-pgtriggerdjango-pgtriggerhelps you writePostgres triggersfor 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 (pgtrigger.Protect).Making read-only models or fields (pgtrigger.ReadOnly).Soft-deleting models (pgtrigger.SoftDelete).Snapshotting and tracking model changes (django-pghistory).Enforcing field transitions (pgtrigger.FSM).Keeping a search vector updated for full-text search (pgtrigger.UpdateSearchVector).Building official interfaces (e.g. enforcing use ofUser.objects.create_userand notUser.objects.create).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.Quick startInstalldjango-pgtriggerwithpip3 install django-pgtriggerand addpgtriggertosettings.INSTALLED_APPS.pgtrigger.Triggerobjects are added totriggersin modelMeta.django-pgtriggercomes with several trigger classes, such aspgtrigger.Protect. In the following, we're protecting the model from being deleted:importpgtriggerclassProtectedModel(models.Model):"""This model cannot be deleted!"""classMeta:triggers=[pgtrigger.Protect(name="protect_deletes",operation=pgtrigger.Delete)]When migrations are created and executed,ProtectedModelwill 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 (theOLDrow in trigger terminology) is still active:importpgtriggerclassProtectedModel(models.Model):"""Active object cannot be deleted!"""is_active=models.BooleanField(default=True)classMeta:triggers=[pgtrigger.Protect(name="protect_deletes",operation=pgtrigger.Delete,condition=pgtrigger.Q(old__is_active=True))]django-pgtriggerusespgtrigger.Qandpgtrigger.Fobjects to conditionally execute triggers based on theOLDandNEWrows. Combining these Django idioms withpgtrigger.Triggerobjects 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. Runpython manage.py makemigrationsandpython manage.py migrateto install triggers.If triggers are new to you, don't worry. Thepgtrigger docscover triggers in more detail and provide many examples.Compatibilitydjango-pgtriggeris compatible with Python 3.8 - 3.12, Django 3.2 - 5.0, Psycopg 2 - 3, and Postgres 12 - 16.DocumentationView the django-pgtrigger docs hereto learn more about:Trigger basics and motivation for using triggers.How to use the built-in triggers and how to build custom ones.Installing triggers on third-party models, many-to-many fields, and other advanced scenarios.Writing conditional triggers.Ignoring triggers dynamically and deferring trigger execution.Multiple database, schema, and partitioning support.Frequently asked questions, common issues, and upgrading.The commands, settings, and module.InstallationInstalldjango-pgtriggerwith:pip3 install django-pgtriggerAfter this, addpgtriggerto theINSTALLED_APPSsetting of your Django project.Other MaterialAfter you've read the docs, check outthis tutorialwith interactive examples from a Django meetup talk.TheDjangoCon 2021 talkalso breaks down triggers and shows several examples.Contributing GuideFor information on setting up django-pgtrigger for development and contributing changes, viewCONTRIBUTING.md.Primary AuthorsWes KendallOther Contributors@jzmiller1@rrauenza@ralokt@adamchainz@danifus@kekekekule@peterthomassen@pfouque