{"id":23159930,"url":"https://github.com/AmbitionEng/django-pgtrigger","last_synced_at":"2025-08-18T02:31:33.722Z","repository":{"id":43677444,"uuid":"275277603","full_name":"AmbitionEng/django-pgtrigger","owner":"AmbitionEng","description":"Write Postgres triggers for your Django models","archived":false,"fork":false,"pushed_at":"2025-06-12T11:59:59.000Z","size":800,"stargazers_count":606,"open_issues_count":9,"forks_count":44,"subscribers_count":10,"default_branch":"main","last_synced_at":"2025-08-11T03:43:41.216Z","etag":null,"topics":["django","postgresql","triggers"],"latest_commit_sha":null,"homepage":"https://django-pgtrigger.readthedocs.io","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AmbitionEng.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":"wesleykendall"}},"created_at":"2020-06-27T01:20:41.000Z","updated_at":"2025-08-07T08:26:20.000Z","dependencies_parsed_at":"2024-06-18T15:26:42.290Z","dependency_job_id":"519c0818-47c4-407b-9ea6-a8117fe138e2","html_url":"https://github.com/AmbitionEng/django-pgtrigger","commit_stats":{"total_commits":108,"total_committers":14,"mean_commits":7.714285714285714,"dds":0.6296296296296297,"last_synced_commit":"9cf9e61f65f5bb5c95756e4e645cafe6e582b097"},"previous_names":["ambitioneng/django-pgtrigger","opus10/django-pgtrigger"],"tags_count":57,"template":false,"template_full_name":null,"purl":"pkg:github/AmbitionEng/django-pgtrigger","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AmbitionEng%2Fdjango-pgtrigger","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AmbitionEng%2Fdjango-pgtrigger/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AmbitionEng%2Fdjango-pgtrigger/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AmbitionEng%2Fdjango-pgtrigger/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AmbitionEng","download_url":"https://codeload.github.com/AmbitionEng/django-pgtrigger/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AmbitionEng%2Fdjango-pgtrigger/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270933599,"owners_count":24670443,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-18T02:00:08.743Z","response_time":89,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["django","postgresql","triggers"],"created_at":"2024-12-17T23:00:31.459Z","updated_at":"2025-08-18T02:31:33.714Z","avatar_url":"https://github.com/AmbitionEng.png","language":"Python","readme":"# django-pgtrigger\n\n`django-pgtrigger` helps you write [Postgres triggers](https://www.postgresql.org/docs/current/sql-createtrigger.html) for your Django models.\n\n## Why should I use triggers?\n\nTriggers can solve a variety of complex problems more reliably, performantly, and succinctly than application code.\nFor example,\n\n* Protecting operations on rows or columns (`pgtrigger.Protect`).\n* Making read-only models or fields (`pgtrigger.ReadOnly`).\n* Soft-deleting models (`pgtrigger.SoftDelete`).\n* Snapshotting and tracking model changes ([django-pghistory](https://django-pghistory.readthedocs.io/)).\n* Enforcing field transitions (`pgtrigger.FSM`).\n* Keeping a search vector updated for full-text search (`pgtrigger.UpdateSearchVector`).\n* Building official interfaces (e.g. enforcing use of `User.objects.create_user` and not `User.objects.create`).\n* Versioning models, mirroring fields, computing unique model hashes, and the list goes on...\n\nAll of these examples require no overridden methods, no base models, and no signal handling.\n\n## Quick start\n\nInstall `django-pgtrigger` with `pip3 install django-pgtrigger` and add `pgtrigger` to `settings.INSTALLED_APPS`.\n\n`pgtrigger.Trigger` objects are added to `triggers` in model `Meta`. `django-pgtrigger` comes with several trigger classes, such as `pgtrigger.Protect`. In the following, we're protecting the model from being deleted:\n\n```python\nimport pgtrigger\n\nclass ProtectedModel(models.Model):\n    \"\"\"This model cannot be deleted!\"\"\"\n\n    class Meta:\n        triggers = [\n            pgtrigger.Protect(name=\"protect_deletes\", operation=pgtrigger.Delete)\n        ]\n```\n\nWhen migrations are created and executed, `ProtectedModel` will raise an exception anytime a deletion is attempted.\n\nLet's extend this example further and only protect deletions on inactive objects. In this example, the trigger conditionally runs when the row being deleted (the `OLD` row in trigger terminology) is still active:\n\n```python\nimport pgtrigger\n\nclass ProtectedModel(models.Model):\n    \"\"\"Active object cannot be deleted!\"\"\"\n    is_active = models.BooleanField(default=True)\n\n    class Meta:\n        triggers = [\n            pgtrigger.Protect(\n                name=\"protect_deletes\",\n                operation=pgtrigger.Delete,\n                condition=pgtrigger.Q(old__is_active=True)\n            )\n        ]\n```\n\n`django-pgtrigger` uses `pgtrigger.Q` and `pgtrigger.F` objects to conditionally execute triggers based on the `OLD` and `NEW` rows. Combining these Django idioms with `pgtrigger.Trigger` objects can solve a wide variety of problems without ever writing SQL. Users, however, can still use raw SQL for complex cases.\n\nTriggers are installed like other database objects. Run `python manage.py makemigrations` and `python manage.py migrate` to install triggers.\n\nIf triggers are new to you, don't worry. The [pgtrigger docs](https://django-pgtrigger.readthedocs.io/) cover triggers in more detail and provide many examples.\n\n## Compatibility\n\n`django-pgtrigger` is compatible with Python 3.9 - 3.13, Django 4.2 - 5.2, Psycopg 2 - 3, and Postgres 14 - 17.\n\n## Documentation\n\n[View the django-pgtrigger docs here](https://django-pgtrigger.readthedocs.io/) to learn more about:\n\n* Trigger basics and motivation for using triggers.\n* How to use the built-in triggers and how to build custom ones.\n* Installing triggers on third-party models, many-to-many fields, and other advanced scenarios.\n* Writing conditional triggers.\n* Ignoring triggers dynamically and deferring trigger execution.\n* Multiple database, schema, and partitioning support.\n* Frequently asked questions, common issues, and upgrading.\n* The commands, settings, and module.\n\n## Installation\n\nInstall `django-pgtrigger` with:\n\n    pip3 install django-pgtrigger\nAfter this, add `pgtrigger` to the `INSTALLED_APPS` setting of your Django project.\n\n## Other Material\n\nAfter you've read the docs, check out [this tutorial](https://wesleykendall.github.io/django-pgtrigger-tutorial/) with interactive examples from a Django meetup talk.\n\nThe [DjangoCon 2021 talk](https://www.youtube.com/watch?v=Tte3d4JjxCk) also breaks down triggers and shows several examples.\n\n## Contributing Guide\n\nFor information on setting up django-pgtrigger for development and contributing changes, view [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## Creators\n\n- [Wes Kendall](https://github.com/wesleykendall)\n\n## Other Contributors\n\n- @jzmiller1\n- @rrauenza\n- @ralokt\n- @adamchainz\n- @danifus\n- @kekekekule\n- @peterthomassen\n- @pfouque\n","funding_links":["https://github.com/sponsors/wesleykendall"],"categories":["Python"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FAmbitionEng%2Fdjango-pgtrigger","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FAmbitionEng%2Fdjango-pgtrigger","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FAmbitionEng%2Fdjango-pgtrigger/lists"}