Advanced Installation

Third-party models

Install triggers on third-party models by declaring them on a proxy model. For example, here we protect Django’s User models from being deleted:

class UserProxy(User):
    class Meta:
        proxy = True
        triggers = [
            pgtrigger.Protect(name='protect_deletes', operation=pgtrigger.Delete)
        ]

Default many-to-many “through” models

Similar to third-party models, we can also install triggers against default many-to-many “through” models by using a proxy model. Here we protect Django User group relationships from being deleted:

class UserGroupTriggers(User.groups.through):
    class Meta:
        proxy = True
        triggers = [
            pgtrigger.Protect(name='protect_deletes', operation=pgtrigger.Delete)
        ]

Warning

Django doesn’t fully support making proxy models from default through relationships. Reversing migrations can sometimes throw InvalidBases errors. We recommend creating a custom through model when possible. See the Django docs on making custom “through” models.

Declaring triggers in base models

Triggers can be declared in an abstract model and inherited. Here is a base model for soft-delete models:

class BaseSoftDelete(models.Model):
    is_active = models.BooleanField(default=True)

    class Meta:
        abstract = True
        triggers = [pgtrigger.SoftDelete(name="soft_delete", field="is_active")]

Keep in mind that Meta class inheritance follows standard Django convention. If the child model defines a Meta class, you will need to inherit the parent’s Meta class like so:

class ChildModel(BaseSoftDelete):
    class Meta(BaseSoftDelete.Meta):
        ordering = ["is_active"]

Programmatically registering triggers

Triggers can be registered programmatically with pgtrigger.register. It can be used as a decorator on a model or called like so:

# Register a protection trigger for a model
pgtrigger.register(pgtrigger.Protect(...))(MyModel)

Warning

Although triggers can be registered programmatically, we don’t recommend doing this except for advanced use cases. Registering a trigger to a model of a third-party app will create migrations in that app. This could result in migrations not being added to your codebase, which can result in triggers not being installed.

Turning off migration integration

django-pgtrigger patches Django’s migration system so that triggers are installed and updated in migrations. If this is undesirable, you can disable the migration integration by setting settings.PGTRIGGER_MIGRATIONS to False. After this, you are left with two options:

  1. Manually install triggers with the commands detailed in the next section.

  2. Run trigger installation after every python manage.py migrate by setting settings.PGTRIGGER_INSTALL_ON_MIGRATE to True. Keep in mind that reversing migrations can cause issues when installing triggers this way.

Manual installation, enabling, and disabling

Warning

Installing, uninstalling, enabling, and disabling triggers are global operations that call ALTER on the table. These should never be called in application code, and they will also interfere with migrations. Only use them when absolutely necessary or when manually managing trigger installations outside of migrations. If you want to temporarily ignore a trigger in an application, see the Ignoring Execution section.

Sometimes one may need to manage installed triggers outside of the Django migration system or turn off migrations by setting settings.PGTRIGGER_MIGRATIONS to False. The following functions manage trigger installation, and each one has an associated management command in the Commands section:

Showing installation status

Use python manage.py pgtrigger ls to see the installation status of individual triggers or all triggers at once. View the Commands section for descriptions of the different installation states.