Django doesn't provide transaction signals because they're a bad idea. Some of the reasons will be apparent in the "Limitations" paragraph below. Other reasons can be found in ticket 14051 and on the django-developers mailing list. However, I'm fed up with having this argument. People will shoot themselves into the foot anyway.
This package will help you experience the problems of transaction signals first-hand.
Use it at your own risk. I wouldn't.
Add 'transaction_signals'
to your INSTALLED_APPS
setting.
This will monkey-patch Django's transaction management features.
You can then register receivers for transaction signals:
from django.dispatch import receiver from transaction_signals import post_commit @receiver(post_commit) def print_commits(sender, **kwargs): print("COMMIT on %s" % sender)
Signals are available in the transaction_signals
package. Their semantics
are obvious, except when they aren't.
Connection signals:
pre_open
post_open
pre_close
post_close
Autocommit signals:
pre_set_autocommit
post_set_autocommit
Transaction signals:
pre_commit
post_commit
pre_rollback
post_rollback
Savepoint signals:
pre_savepoint
post_savepoint
pre_savepoint_commit
post_savepoint_commit
pre_savepoint_rollback
post_savepoint_rollback
sender
is the alias of the database connection e.g. 'default'
. All
signals pass the database connection in the 'connection'
argument.
Furthermore, pre/post_open
provide a conn_params
argument,
pre/post_set_autocommit
provide autocommit
, and
pre/post_savepoint/_commit/_rollback
provide savepoint_id
.
You cannot assume that pre/post_commit
are sent whenever changes are
committed. Signals aren't sent when the connection is in autocommit mode,
which is the default.
You cannot assume that pre/post_rollback
are sent whenever changes are
cancelled. Closing the connection to the database triggers an implicit
rollback.
You cannot assume that pre/post_close
are sent whenever an implicit
rollback happens. Losing the connection to the database also triggers an
implicit rollback.
After pre/post_savepoint
is sent, you cannot assume that either
pre/post_savepoint_commit
or pre/post_savepoint_rollback
will be sent
with the same savepoint_id
. The savepoint may be released or rolled back
together with an earlier savepoint or the entire transaction.
You cannot use pre/post_set_autocommit
on SQLite. The sqlite3
module
doesn't work in non-autocommit mode.
You cannot use pre/post_savepoint_commit
on Oracle. Oracle doesn't support
releasing savepoints.
This is only the tip of the iceberg. I cannot recommend you use this package if you learnt anything in this section. In fact, I cannot recommend it at all.
Fortunately, if you want to add custom logic to Django's transaction handling, you have several alternatives. They're much less likely to result in anger, facepalms, insanity, loss of self-esteem, and other regrettable side effects.
You may put your custom logic:
- In a middleware, if you only care about transactions tied to requests when
ATOMIC_REQUESTS
is enabled. - In a decorator that wraps
atomic
, if you have more advanced needs, especially if you want to track partial commits and rollbacks. - In a database backend, if you want tight control over database operations. Since there's no public API, you'll have to read the source and figure out how Django works, rather than blindly hooking to signals that may or may not be sent.
This package is released under a dual license: WTFPLv2 and GPLv2.
The distribution only includes the WTFPLv2 because the GPLv2 is too long.