File: ignoring_triggers.md

package info (click to toggle)
python-django-pgtrigger 4.15.3-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 956 kB
  • sloc: python: 4,412; makefile: 114; sh: 8; sql: 2
file content (57 lines) | stat: -rw-r--r-- 2,521 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# Ignoring Execution

## Overview

[pgtrigger.ignore][] is a decorator and context manager that temporarily ignores triggers for a single
thread of execution. Here we ignore deletion protection:

```python
class CannotDelete(models.Model):
    class Meta:
        triggers = [
            pgtrigger.Protect(name="protect_deletes", operation=pgtrigger.Delete)
        ]


# Bypass deletion protection
with pgtrigger.ignore("my_app.CannotDelete:protect_deletes"):
    CannotDelete.objects.all().delete()
```

As shown above, [pgtrigger.ignore][] takes a trigger URI that is formatted as `{app_label}.{model_name}:{trigger_name}`. Multiple trigger URIs can be given to [pgtrigger.ignore][], and [pgtrigger.ignore][] can be nested. If no trigger URIs are provided to [pgtrigger.ignore][], all triggers are ignored.

!!! tip

    See all trigger URIs with `python manage.py pgtrigger ls`

By default, [pgtrigger.ignore][] configures ignoring triggers on every postgres database. This can be changed with the `databases` argument.

!!! important

    Remember, [pgtrigger.ignore][] ignores the execution of a trigger on a per-thread basis. This is very different from disabling a trigger or uninstalling a trigger globally. See the [Advanced Installation](advanced_installation.md) section for more details on managing the installation of triggers.

## Transaction notes

[pgtrigger.ignore][] flushes a temporary Postgres variable at the end of the context manager if running in a transaction. This could cause issues for transactions that are in an errored state.

Here's an example of when this case happens:

```python
with transaction.atomic():
    with ptrigger.ignore("app.Model:protect_inserts"):
        try:
            # Create an object that raises an integrity error
            app.Model.objects.create(unique_key="duplicate")
        except IntegrityError:
            # Ignore the integrity error
            pass

    # When we exit the context manager here, it will try to flush
    # a local Postgres variable. This causes an error because the transaction
    # is in an errored state.
```

If you're ignoring triggers and handling database errors, there are two ways to prevent this error from happening:

1. Wrap the outer transaction in `with pgtrigger.ignore.session():` so that the session is completed outside the transaction.
2. Wrap the inner `try/except` in `with transaction.atomic():` so that the errored part of the transaction is rolled back before the [pgtrigger.ignore][] context manager ends.