| 1 |
============================== |
|---|
| 2 |
Managing database transactions |
|---|
| 3 |
============================== |
|---|
| 4 |
|
|---|
| 5 |
Django gives you a few ways to control how database transactions are managed, |
|---|
| 6 |
if you're using a database that supports transactions. |
|---|
| 7 |
|
|---|
| 8 |
Django's default transaction behavior |
|---|
| 9 |
===================================== |
|---|
| 10 |
|
|---|
| 11 |
Django's default behavior is to commit automatically when any built-in, |
|---|
| 12 |
data-altering model function is called. For example, if you call |
|---|
| 13 |
``model.save()`` or ``model.delete()``, the change will be committed |
|---|
| 14 |
immediately. |
|---|
| 15 |
|
|---|
| 16 |
This is much like the auto-commit setting for most databases. As soon as you |
|---|
| 17 |
perform an action that needs to write to the database, Django produces the |
|---|
| 18 |
``INSERT``/``UPDATE``/``DELETE`` statements and then does the ``COMMIT``. |
|---|
| 19 |
There's no implicit ``ROLLBACK``. |
|---|
| 20 |
|
|---|
| 21 |
Tying transactions to HTTP requests |
|---|
| 22 |
=================================== |
|---|
| 23 |
|
|---|
| 24 |
The recommended way to handle transactions in Web requests is to tie them to |
|---|
| 25 |
the request and response phases via Django's ``TransactionMiddleware``. |
|---|
| 26 |
|
|---|
| 27 |
It works like this: When a request starts, Django starts a transaction. If the |
|---|
| 28 |
response is produced without problems, Django commits any pending transactions. |
|---|
| 29 |
If the view function produces an exception, Django rolls back any pending |
|---|
| 30 |
transactions. |
|---|
| 31 |
|
|---|
| 32 |
To activate this feature, just add the ``TransactionMiddleware`` middleware to |
|---|
| 33 |
your ``MIDDLEWARE_CLASSES`` setting:: |
|---|
| 34 |
|
|---|
| 35 |
MIDDLEWARE_CLASSES = ( |
|---|
| 36 |
'django.contrib.sessions.middleware.SessionMiddleware', |
|---|
| 37 |
'django.middleware.common.CommonMiddleware', |
|---|
| 38 |
'django.middleware.cache.CacheMiddleware', |
|---|
| 39 |
'django.middleware.transaction.TransactionMiddleware', |
|---|
| 40 |
) |
|---|
| 41 |
|
|---|
| 42 |
The order is quite important. The transaction middleware applies not only to |
|---|
| 43 |
view functions, but also for all middleware modules that come after it. So if |
|---|
| 44 |
you use the session middleware after the transaction middleware, session |
|---|
| 45 |
creation will be part of the transaction. |
|---|
| 46 |
|
|---|
| 47 |
An exception is ``CacheMiddleware``, which is never affected. The cache |
|---|
| 48 |
middleware uses its own database cursor (which is mapped to its own database |
|---|
| 49 |
connection internally). |
|---|
| 50 |
|
|---|
| 51 |
Controlling transaction management in views |
|---|
| 52 |
=========================================== |
|---|
| 53 |
|
|---|
| 54 |
For most people, implicit request-based transactions work wonderfully. However, |
|---|
| 55 |
if you need more fine-grained control over how transactions are managed, you |
|---|
| 56 |
can use Python decorators to change the way transactions are handled by a |
|---|
| 57 |
particular view function. |
|---|
| 58 |
|
|---|
| 59 |
.. note:: |
|---|
| 60 |
|
|---|
| 61 |
Although the examples below use view functions as examples, these |
|---|
| 62 |
decorators can be applied to non-view functions as well. |
|---|
| 63 |
|
|---|
| 64 |
``django.db.transaction.autocommit`` |
|---|
| 65 |
------------------------------------ |
|---|
| 66 |
|
|---|
| 67 |
Use the ``autocommit`` decorator to switch a view function to Django's default |
|---|
| 68 |
commit behavior, regardless of the global transaction setting. |
|---|
| 69 |
|
|---|
| 70 |
Example:: |
|---|
| 71 |
|
|---|
| 72 |
from django.db import transaction |
|---|
| 73 |
|
|---|
| 74 |
@transaction.autocommit |
|---|
| 75 |
def viewfunc(request): |
|---|
| 76 |
.... |
|---|
| 77 |
|
|---|
| 78 |
Within ``viewfunc()``, transactions will be committed as soon as you call |
|---|
| 79 |
``model.save()``, ``model.delete()``, or any other function that writes to the |
|---|
| 80 |
database. |
|---|
| 81 |
|
|---|
| 82 |
``django.db.transaction.commit_on_success`` |
|---|
| 83 |
------------------------------------------- |
|---|
| 84 |
|
|---|
| 85 |
Use the ``commit_on_success`` decorator to use a single transaction for |
|---|
| 86 |
all the work done in a function:: |
|---|
| 87 |
|
|---|
| 88 |
from django.db import transaction |
|---|
| 89 |
|
|---|
| 90 |
@transaction.commit_on_success |
|---|
| 91 |
def viewfunc(request): |
|---|
| 92 |
.... |
|---|
| 93 |
|
|---|
| 94 |
If the function returns successfully, then Django will commit all work done |
|---|
| 95 |
within the function at that point. If the function raises an exception, though, |
|---|
| 96 |
Django will roll back the transaction. |
|---|
| 97 |
|
|---|
| 98 |
``django.db.transaction.commit_manually`` |
|---|
| 99 |
----------------------------------------- |
|---|
| 100 |
|
|---|
| 101 |
Use the ``commit_manually`` decorator if you need full control over |
|---|
| 102 |
transactions. It tells Django you'll be managing the transaction on your own. |
|---|
| 103 |
|
|---|
| 104 |
If your view changes data and doesn't ``commit()`` or ``rollback()``, Django |
|---|
| 105 |
will raise a ``TransactionManagementError`` exception. |
|---|
| 106 |
|
|---|
| 107 |
Manual transaction management looks like this:: |
|---|
| 108 |
|
|---|
| 109 |
from django.db import transaction |
|---|
| 110 |
|
|---|
| 111 |
@transaction.commit_manually |
|---|
| 112 |
def viewfunc(request): |
|---|
| 113 |
... |
|---|
| 114 |
# You can commit/rollback however and whenever you want |
|---|
| 115 |
transaction.commit() |
|---|
| 116 |
... |
|---|
| 117 |
|
|---|
| 118 |
# But you've got to remember to do it yourself! |
|---|
| 119 |
try: |
|---|
| 120 |
... |
|---|
| 121 |
except: |
|---|
| 122 |
transaction.rollback() |
|---|
| 123 |
else: |
|---|
| 124 |
transaction.commit() |
|---|
| 125 |
|
|---|
| 126 |
.. admonition:: An important note to users of earlier Django releases: |
|---|
| 127 |
|
|---|
| 128 |
The database ``connection.commit()`` and ``connection.rollback()`` methods |
|---|
| 129 |
(called ``db.commit()`` and ``db.rollback()`` in 0.91 and earlier) no longer |
|---|
| 130 |
exist. They've been replaced by ``transaction.commit()`` and |
|---|
| 131 |
``transaction.rollback()``. |
|---|
| 132 |
|
|---|
| 133 |
How to globally deactivate transaction management |
|---|
| 134 |
================================================= |
|---|
| 135 |
|
|---|
| 136 |
Control freaks can totally disable all transaction management by setting |
|---|
| 137 |
``DISABLE_TRANSACTION_MANAGEMENT`` to ``True`` in the Django settings file. |
|---|
| 138 |
|
|---|
| 139 |
If you do this, Django won't provide any automatic transaction management |
|---|
| 140 |
whatsoever. Middleware will no longer implicitly commit transactions, and |
|---|
| 141 |
you'll need to roll management yourself. This even requires you to commit |
|---|
| 142 |
changes done by middleware somewhere else. |
|---|
| 143 |
|
|---|
| 144 |
Thus, this is best used in situations where you want to run your own |
|---|
| 145 |
transaction-controlling middleware or do something really strange. In almost |
|---|
| 146 |
all situations, you'll be better off using the default behavior, or the |
|---|
| 147 |
transaction middleware, and only modify selected functions as needed. |
|---|
| 148 |
|
|---|
| 149 |
Transactions in MySQL |
|---|
| 150 |
===================== |
|---|
| 151 |
|
|---|
| 152 |
If you're using MySQL, your tables may or may not support transactions; it |
|---|
| 153 |
depends on your MySQL version and the table types you're using. (By |
|---|
| 154 |
"table types," we mean something like "InnoDB" or "MyISAM".) MySQL transaction |
|---|
| 155 |
peculiarities are outside the scope of this article, but the MySQL site has |
|---|
| 156 |
`information on MySQL transactions`_. |
|---|
| 157 |
|
|---|
| 158 |
If your MySQL setup does *not* support transactions, then Django will function |
|---|
| 159 |
in auto-commit mode: Statements will be executed and committed as soon as |
|---|
| 160 |
they're called. If your MySQL setup *does* support transactions, Django will |
|---|
| 161 |
handle transactions as explained in this document. |
|---|
| 162 |
|
|---|
| 163 |
.. _information on MySQL transactions: http://dev.mysql.com/books/mysqlpress/mysql-tutorial/ch10.html |
|---|