summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
Diffstat (limited to 'docs')
-rw-r--r--docs/internals/deprecation.txt19
-rw-r--r--docs/ref/databases.txt59
-rw-r--r--docs/ref/middleware.txt4
-rw-r--r--docs/ref/request-response.txt4
-rw-r--r--docs/ref/settings.txt30
-rw-r--r--docs/releases/1.3-alpha-1.txt6
-rw-r--r--docs/releases/1.3.txt6
-rw-r--r--docs/releases/1.6.txt37
-rw-r--r--docs/topics/db/sql.txt61
-rw-r--r--docs/topics/db/transactions.txt734
10 files changed, 653 insertions, 307 deletions
diff --git a/docs/internals/deprecation.txt b/docs/internals/deprecation.txt
index b5173af298..19675801e4 100644
--- a/docs/internals/deprecation.txt
+++ b/docs/internals/deprecation.txt
@@ -329,6 +329,15 @@ these changes.
1.8
---
+* The following transaction management APIs will be removed:
+
+ - ``TransactionMiddleware``,
+ - the decorators and context managers ``autocommit``, ``commit_on_success``,
+ and ``commit_manually``,
+ - the ``TRANSACTIONS_MANAGED`` setting.
+
+ Upgrade paths are described in :ref:`transactions-upgrading-from-1.5`.
+
* The :ttag:`cycle` and :ttag:`firstof` template tags will auto-escape their
arguments. In 1.6 and 1.7, this behavior is provided by the version of these
tags in the ``future`` template tag library.
@@ -339,8 +348,6 @@ these changes.
* ``Model._meta.module_name`` was renamed to ``model_name``.
-* The private API ``django.db.close_connection`` will be removed.
-
* Remove the backward compatible shims introduced to rename ``get_query_set``
and similar queryset methods. This affects the following classes:
``BaseModelAdmin``, ``ChangeList``, ``BaseCommentNode``,
@@ -350,6 +357,14 @@ these changes.
* Remove the backward compatible shims introduced to rename the attributes
``ChangeList.root_query_set`` and ``ChangeList.query_set``.
+* The following private APIs will be removed:
+ - ``django.db.close_connection()``
+ - ``django.db.backends.creation.BaseDatabaseCreation.set_autocommit()``
+ - ``django.db.transaction.is_managed()``
+ - ``django.db.transaction.managed()``
+ - ``django.db.transaction.commit_unless_managed()``
+ - ``django.db.transaction.rollback_unless_managed()``
+
2.0
---
diff --git a/docs/ref/databases.txt b/docs/ref/databases.txt
index 4e435949a2..78c1bb3dda 100644
--- a/docs/ref/databases.txt
+++ b/docs/ref/databases.txt
@@ -69,7 +69,6 @@ even ``0``, because it doesn't make sense to maintain a connection that's
unlikely to be reused. This will help keep the number of simultaneous
connections to this database small.
-
The development server creates a new thread for each request it handles,
negating the effect of persistent connections.
@@ -104,7 +103,8 @@ Optimizing PostgreSQL's configuration
Django needs the following parameters for its database connections:
- ``client_encoding``: ``'UTF8'``,
-- ``default_transaction_isolation``: ``'read committed'``,
+- ``default_transaction_isolation``: ``'read committed'`` by default,
+ or the value set in the connection options (see below),
- ``timezone``: ``'UTC'`` when :setting:`USE_TZ` is ``True``, value of
:setting:`TIME_ZONE` otherwise.
@@ -118,30 +118,16 @@ will do some additional queries to set these parameters.
.. _ALTER ROLE: http://www.postgresql.org/docs/current/interactive/sql-alterrole.html
-Transaction handling
----------------------
-
-:doc:`By default </topics/db/transactions>`, Django runs with an open
-transaction which it commits automatically when any built-in, data-altering
-model function is called. The PostgreSQL backends normally operate the same as
-any other Django backend in this respect.
-
.. _postgresql-autocommit-mode:
Autocommit mode
-~~~~~~~~~~~~~~~
+---------------
-If your application is particularly read-heavy and doesn't make many
-database writes, the overhead of a constantly open transaction can
-sometimes be noticeable. For those situations, you can configure Django
-to use *"autocommit"* behavior for the connection, meaning that each database
-operation will normally be in its own transaction, rather than having
-the transaction extend over multiple operations. In this case, you can
-still manually start a transaction if you're doing something that
-requires consistency across multiple database operations. The
-autocommit behavior is enabled by setting the ``autocommit`` key in
-the :setting:`OPTIONS` part of your database configuration in
-:setting:`DATABASES`::
+.. versionchanged:: 1.6
+
+In previous versions of Django, database-level autocommit could be enabled by
+setting the ``autocommit`` key in the :setting:`OPTIONS` part of your database
+configuration in :setting:`DATABASES`::
DATABASES = {
# ...
@@ -150,29 +136,11 @@ the :setting:`OPTIONS` part of your database configuration in
},
}
-In this configuration, Django still ensures that :ref:`delete()
-<topics-db-queries-delete>` and :ref:`update() <topics-db-queries-update>`
-queries run inside a single transaction, so that either all the affected
-objects are changed or none of them are.
-
-.. admonition:: This is database-level autocommit
-
- This functionality is not the same as the :ref:`autocommit
- <topics-db-transactions-autocommit>` decorator. That decorator is
- a Django-level implementation that commits automatically after
- data changing operations. The feature enabled using the
- :setting:`OPTIONS` option provides autocommit behavior at the
- database adapter level. It commits after *every* operation.
-
-If you are using this feature and performing an operation akin to delete or
-updating that requires multiple operations, you are strongly recommended to
-wrap you operations in manual transaction handling to ensure data consistency.
-You should also audit your existing code for any instances of this behavior
-before enabling this feature. It's faster, but it provides less automatic
-protection for multi-call operations.
+Since Django 1.6, autocommit is turned on by default. This configuration is
+ignored and can be safely removed.
Isolation level
-~~~~~~~~~~~~~~~
+---------------
.. versionadded:: 1.6
@@ -200,7 +168,7 @@ such as ``REPEATABLE READ`` or ``SERIALIZABLE``, set it in the
.. _postgresql-isolation-levels: http://www.postgresql.org/docs/devel/static/transaction-iso.html
Indexes for ``varchar`` and ``text`` columns
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+--------------------------------------------
When specifying ``db_index=True`` on your model fields, Django typically
outputs a single ``CREATE INDEX`` statement. However, if the database type
@@ -456,8 +424,7 @@ Savepoints
Both the Django ORM and MySQL (when using the InnoDB :ref:`storage engine
<mysql-storage-engines>`) support database :ref:`savepoints
-<topics-db-transactions-savepoints>`, but this feature wasn't available in
-Django until version 1.4 when such supports was added.
+<topics-db-transactions-savepoints>`.
If you use the MyISAM storage engine please be aware of the fact that you will
receive database-generated errors if you try to use the :ref:`savepoint-related
diff --git a/docs/ref/middleware.txt b/docs/ref/middleware.txt
index 1e6e57f720..20bb2fb751 100644
--- a/docs/ref/middleware.txt
+++ b/docs/ref/middleware.txt
@@ -205,6 +205,10 @@ Transaction middleware
.. class:: TransactionMiddleware
+.. versionchanged:: 1.6
+ ``TransactionMiddleware`` is deprecated. The documentation of transactions
+ contains :ref:`upgrade instructions <transactions-upgrading-from-1.5>`.
+
Binds commit and rollback of the default database to the request/response
phase. If a view function runs successfully, a commit is done. If it fails with
an exception, a rollback is done.
diff --git a/docs/ref/request-response.txt b/docs/ref/request-response.txt
index 30f5e87100..6f620e17e2 100644
--- a/docs/ref/request-response.txt
+++ b/docs/ref/request-response.txt
@@ -814,8 +814,8 @@ generating large CSV files.
.. admonition:: Performance considerations
Django is designed for short-lived requests. Streaming responses will tie
- a worker process and keep a database connection idle in transaction for
- the entire duration of the response. This may result in poor performance.
+ a worker process for the entire duration of the response. This may result
+ in poor performance.
Generally speaking, you should perform expensive tasks outside of the
request-response cycle, rather than resorting to a streamed response.
diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt
index 0cd141bcef..2b80527d8b 100644
--- a/docs/ref/settings.txt
+++ b/docs/ref/settings.txt
@@ -408,6 +408,30 @@ SQLite. This can be configured using the following::
For other database backends, or more complex SQLite configurations, other options
will be required. The following inner options are available.
+.. setting:: DATABASE-ATOMIC_REQUESTS
+
+ATOMIC_REQUESTS
+~~~~~~~~~~~~~~~
+
+.. versionadded:: 1.6
+
+Default: ``False``
+
+Set this to ``True`` to wrap each HTTP request in a transaction on this
+database. See :ref:`tying-transactions-to-http-requests`.
+
+.. setting:: DATABASE-AUTOCOMMIT
+
+AUTOCOMMIT
+~~~~~~~~~~
+
+.. versionadded:: 1.6
+
+Default: ``True``
+
+Set this to ``False`` if you want to :ref:`disable Django's transaction
+management <deactivate-transaction-management>` and implement your own.
+
.. setting:: DATABASE-ENGINE
ENGINE
@@ -1807,6 +1831,12 @@ to ensure your processes are running in the correct environment.
TRANSACTIONS_MANAGED
--------------------
+.. deprecated:: 1.6
+
+ This setting was deprecated because its name is very misleading. Use the
+ :setting:`AUTOCOMMIT <DATABASE-AUTOCOMMIT>` key in :setting:`DATABASES`
+ entries instead.
+
Default: ``False``
Set this to ``True`` if you want to :ref:`disable Django's transaction
diff --git a/docs/releases/1.3-alpha-1.txt b/docs/releases/1.3-alpha-1.txt
index ba8a4fc557..53d38a006b 100644
--- a/docs/releases/1.3-alpha-1.txt
+++ b/docs/releases/1.3-alpha-1.txt
@@ -105,16 +105,14 @@ you just won't get any of the nice new unittest2 features.
Transaction context managers
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Users of Python 2.5 and above may now use :ref:`transaction management functions
-<transaction-management-functions>` as `context managers`_. For example::
+Users of Python 2.5 and above may now use transaction management functions as
+`context managers`_. For example::
with transaction.autocommit():
# ...
.. _context managers: http://docs.python.org/glossary.html#term-context-manager
-For more information, see :ref:`transaction-management-functions`.
-
Configurable delete-cascade
~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/releases/1.3.txt b/docs/releases/1.3.txt
index 4c8dd2f81f..582bceffca 100644
--- a/docs/releases/1.3.txt
+++ b/docs/releases/1.3.txt
@@ -148,16 +148,14 @@ you just won't get any of the nice new unittest2 features.
Transaction context managers
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Users of Python 2.5 and above may now use :ref:`transaction management functions
-<transaction-management-functions>` as `context managers`_. For example::
+Users of Python 2.5 and above may now use transaction management functions as
+`context managers`_. For example::
with transaction.autocommit():
# ...
.. _context managers: http://docs.python.org/glossary.html#term-context-manager
-For more information, see :ref:`transaction-management-functions`.
-
Configurable delete-cascade
~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/releases/1.6.txt b/docs/releases/1.6.txt
index d78d594c90..a1fe69229c 100644
--- a/docs/releases/1.6.txt
+++ b/docs/releases/1.6.txt
@@ -30,6 +30,18 @@ prevention <clickjacking-prevention>` are turned on.
If the default templates don't suit your tastes, you can use :ref:`custom
project and app templates <custom-app-and-project-templates>`.
+Improved transaction management
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Django's transaction management was overhauled. Database-level autocommit is
+now turned on by default. This makes transaction handling more explicit and
+should improve performance. The existing APIs were deprecated, and new APIs
+were introduced, as described in :doc:`/topics/db/transactions`.
+
+Please review carefully the list of :ref:`known backwards-incompatibilities
+<transactions-upgrading-from-1.5>` to determine if you need to make changes in
+your code.
+
Persistent database connections
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -148,6 +160,16 @@ Backwards incompatible changes in 1.6
deprecation timeline for a given feature, its removal may appear as a
backwards incompatible change.
+* Database-level autocommit is enabled by default in Django 1.6. While this
+ doesn't change the general spirit of Django's transaction management, there
+ are a few known backwards-incompatibities, described in the :ref:`transaction
+ management docs <transactions-upgrading-from-1.5>`. You should review your code
+ to determine if you're affected.
+
+* In previous versions, database-level autocommit was only an option for
+ PostgreSQL, and it was disabled by default. This option is now
+ :ref:`ignored <postgresql-autocommit-mode>`.
+
* The ``django.db.models.query.EmptyQuerySet`` can't be instantiated any more -
it is only usable as a marker class for checking if
:meth:`~django.db.models.query.QuerySet.none` has been called:
@@ -234,6 +256,21 @@ Backwards incompatible changes in 1.6
Features deprecated in 1.6
==========================
+Transaction management APIs
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Transaction management was completely overhauled in Django 1.6, and the
+current APIs are deprecated:
+
+- ``django.middleware.transaction.TransactionMiddleware``
+- ``django.db.transaction.autocommit``
+- ``django.db.transaction.commit_on_success``
+- ``django.db.transaction.commit_manually``
+- the ``TRANSACTIONS_MANAGED`` setting
+
+The reasons for this change and the upgrade path are described in the
+:ref:`transactions documentation <transactions-upgrading-from-1.5>`.
+
Changes to :ttag:`cycle` and :ttag:`firstof`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/docs/topics/db/sql.txt b/docs/topics/db/sql.txt
index 6cc174a248..b2161fe65b 100644
--- a/docs/topics/db/sql.txt
+++ b/docs/topics/db/sql.txt
@@ -201,31 +201,32 @@ perform queries that don't map cleanly to models, or directly execute
In these cases, you can always access the database directly, routing around
the model layer entirely.
-The object ``django.db.connection`` represents the
-default database connection, and ``django.db.transaction`` represents the
-default database transaction. To use the database connection, call
-``connection.cursor()`` to get a cursor object. Then, call
-``cursor.execute(sql, [params])`` to execute the SQL and ``cursor.fetchone()``
-or ``cursor.fetchall()`` to return the resulting rows. After performing a data
-changing operation, you should then call
-``transaction.commit_unless_managed()`` to ensure your changes are committed
-to the database. If your query is purely a data retrieval operation, no commit
-is required. For example::
+The object ``django.db.connection`` represents the default database
+connection. To use the database connection, call ``connection.cursor()`` to
+get a cursor object. Then, call ``cursor.execute(sql, [params])`` to execute
+the SQL and ``cursor.fetchone()`` or ``cursor.fetchall()`` to return the
+resulting rows.
+
+For example::
+
+ from django.db import connection
def my_custom_sql():
- from django.db import connection, transaction
cursor = connection.cursor()
- # Data modifying operation - commit required
cursor.execute("UPDATE bar SET foo = 1 WHERE baz = %s", [self.baz])
- transaction.commit_unless_managed()
- # Data retrieval operation - no commit required
cursor.execute("SELECT foo FROM bar WHERE baz = %s", [self.baz])
row = cursor.fetchone()
return row
+.. versionchanged:: 1.6
+ In Django 1.5 and earlier, after performing a data changing operation, you
+ had to call ``transaction.commit_unless_managed()`` to ensure your changes
+ were committed to the database. Since Django now defaults to database-level
+ autocommit, this isn't necessary any longer.
+
If you are using :doc:`more than one database </topics/db/multi-db>`, you can
use ``django.db.connections`` to obtain the connection (and cursor) for a
specific database. ``django.db.connections`` is a dictionary-like
@@ -235,7 +236,6 @@ alias::
from django.db import connections
cursor = connections['my_db_alias'].cursor()
# Your code here...
- transaction.commit_unless_managed(using='my_db_alias')
By default, the Python DB API will return results without their field
names, which means you end up with a ``list`` of values, rather than a
@@ -260,27 +260,18 @@ Here is an example of the difference between the two::
>>> dictfetchall(cursor)
[{'parent_id': None, 'id': 54360982L}, {'parent_id': None, 'id': 54360880L}]
-
-.. _transactions-and-raw-sql:
-
-Transactions and raw SQL
-------------------------
-
-When you make a raw SQL call, Django will automatically mark the
-current transaction as dirty. You must then ensure that the
-transaction containing those calls is closed correctly. See :ref:`the
-notes on the requirements of Django's transaction handling
-<topics-db-transactions-requirements>` for more details.
-
Connections and cursors
-----------------------
``connection`` and ``cursor`` mostly implement the standard Python DB-API
-described in :pep:`249` (except when it comes to :doc:`transaction handling
-</topics/db/transactions>`). If you're not familiar with the Python DB-API, note
-that the SQL statement in ``cursor.execute()`` uses placeholders, ``"%s"``,
-rather than adding parameters directly within the SQL. If you use this
-technique, the underlying database library will automatically add quotes and
-escaping to your parameter(s) as necessary. (Also note that Django expects the
-``"%s"`` placeholder, *not* the ``"?"`` placeholder, which is used by the SQLite
-Python bindings. This is for the sake of consistency and sanity.)
+described in :pep:`249` — except when it comes to :doc:`transaction handling
+</topics/db/transactions>`.
+
+If you're not familiar with the Python DB-API, note that the SQL statement in
+``cursor.execute()`` uses placeholders, ``"%s"``, rather than adding
+parameters directly within the SQL. If you use this technique, the underlying
+database library will automatically escape your parameters as necessary.
+
+Also note that Django expects the ``"%s"`` placeholder, *not* the ``"?"``
+placeholder, which is used by the SQLite Python bindings. This is for the sake
+of consistency and sanity.
diff --git a/docs/topics/db/transactions.txt b/docs/topics/db/transactions.txt
index 11755ff5c5..b8017e8bfa 100644
--- a/docs/topics/db/transactions.txt
+++ b/docs/topics/db/transactions.txt
@@ -1,286 +1,375 @@
-==============================
-Managing database transactions
-==============================
+=====================
+Database transactions
+=====================
.. module:: django.db.transaction
-Django gives you a few ways to control how database transactions are managed,
-if you're using a database that supports transactions.
+Django gives you a few ways to control how database transactions are managed.
+
+Managing database transactions
+==============================
Django's default transaction behavior
-=====================================
+-------------------------------------
+
+Django's default behavior is to run in autocommit mode. Each query is
+immediately committed to the database. :ref:`See below for details
+<autocommit-details>`.
+
+Django uses transactions or savepoints automatically to guarantee the
+integrity of ORM operations that require multiple queries, especially
+:ref:`delete() <topics-db-queries-delete>` and :ref:`update()
+<topics-db-queries-update>` queries.
-Django's default behavior is to run with an open transaction which it
-commits automatically when any built-in, data-altering model function is
-called. For example, if you call ``model.save()`` or ``model.delete()``, the
-change will be committed immediately.
+.. versionchanged:: 1.6
+ Previous version of Django featured :ref:`a more complicated default
+ behavior <transactions-upgrading-from-1.5>`.
-This is much like the auto-commit setting for most databases. As soon as you
-perform an action that needs to write to the database, Django produces the
-``INSERT``/``UPDATE``/``DELETE`` statements and then does the ``COMMIT``.
-There's no implicit ``ROLLBACK``.
+.. _tying-transactions-to-http-requests:
Tying transactions to HTTP requests
-===================================
+-----------------------------------
-The recommended way to handle transactions in Web requests is to tie them to
-the request and response phases via Django's ``TransactionMiddleware``.
+A common way to handle transactions on the web is to wrap each request in a
+transaction. Set :setting:`ATOMIC_REQUESTS <DATABASE-ATOMIC_REQUESTS>` to
+``True`` in the configuration of each database for which you want to enable
+this behavior.
-It works like this: When a request starts, Django starts a transaction. If the
-response is produced without problems, Django commits any pending transactions.
-If the view function produces an exception, Django rolls back any pending
-transactions.
+It works like this. When a request starts, Django starts a transaction. If the
+response is produced without problems, Django commits the transaction. If the
+view function produces an exception, Django rolls back the transaction.
+Middleware always runs outside of this transaction.
-To activate this feature, just add the ``TransactionMiddleware`` middleware to
-your :setting:`MIDDLEWARE_CLASSES` setting::
+You may perfom partial commits and rollbacks in your view code, typically with
+the :func:`atomic` context manager. However, at the end of the view, either
+all the changes will be committed, or none of them.
- MIDDLEWARE_CLASSES = (
- 'django.middleware.cache.UpdateCacheMiddleware',
- 'django.contrib.sessions.middleware.SessionMiddleware',
- 'django.middleware.common.CommonMiddleware',
- 'django.middleware.transaction.TransactionMiddleware',
- 'django.middleware.cache.FetchFromCacheMiddleware',
- )
+To disable this behavior for a specific view, you must set the
+``transactions_per_request`` attribute of the view function itself to
+``False``, like this::
-The order is quite important. The transaction middleware applies not only to
-view functions, but also for all middleware modules that come after it. So if
-you use the session middleware after the transaction middleware, session
-creation will be part of the transaction.
+ def my_view(request):
+ do_stuff()
+ my_view.transactions_per_request = False
-The various cache middlewares are an exception:
-``CacheMiddleware``, :class:`~django.middleware.cache.UpdateCacheMiddleware`,
-and :class:`~django.middleware.cache.FetchFromCacheMiddleware` are never
-affected. Even when using database caching, Django's cache backend uses its own
-database cursor (which is mapped to its own database connection internally).
+.. warning::
-.. note::
+ While the simplicity of this transaction model is appealing, it also makes it
+ inefficient when traffic increases. Opening a transaction for every view has
+ some overhead. The impact on performance depends on the query patterns of your
+ application and on how well your database handles locking.
- The ``TransactionMiddleware`` only affects the database aliased
- as "default" within your :setting:`DATABASES` setting. If you are using
- multiple databases and want transaction control over databases other than
- "default", you will need to write your own transaction middleware.
+.. admonition:: Per-request transactions and streaming responses
-.. _transaction-management-functions:
+ When a view returns a :class:`~django.http.StreamingHttpResponse`, reading
+ the contents of the response will often execute code to generate the
+ content. Since the view has already returned, such code runs outside of
+ the transaction.
-Controlling transaction management in views
-===========================================
+ Generally speaking, it isn't advisable to write to the database while
+ generating a streaming response, since there's no sensible way to handle
+ errors after starting to send the response.
-For most people, implicit request-based transactions work wonderfully. However,
-if you need more fine-grained control over how transactions are managed, you can
-use a set of functions in ``django.db.transaction`` to control transactions on a
-per-function or per-code-block basis.
+In practice, this feature simply wraps every view function in the :func:`atomic`
+decorator described below.
-These functions, described in detail below, can be used in two different ways:
+Note that only the execution of your view in enclosed in the transactions.
+Middleware run outside of the transaction, and so does the rendering of
+template responses.
-* As a decorator_ on a particular function. For example::
+.. versionchanged:: 1.6
+ Django used to provide this feature via ``TransactionMiddleware``, which is
+ now deprecated.
- from django.db import transaction
+Controlling transactions explicitly
+-----------------------------------
- @transaction.commit_on_success
- def viewfunc(request):
- # ...
- # this code executes inside a transaction
- # ...
+.. versionadded:: 1.6
-* As a `context manager`_ around a particular block of code::
+Django provides a single API to control database transactions.
- from django.db import transaction
+.. function:: atomic(using=None, savepoint=True)
- def viewfunc(request):
- # ...
- # this code executes using default transaction management
- # ...
+ This function creates an atomic block for writes to the database.
+ (Atomicity is the defining property of database transactions.)
- with transaction.commit_on_success():
- # ...
- # this code executes inside a transaction
- # ...
+ When the block completes successfully, the changes are committed to the
+ database. When it raises an exception, the changes are rolled back.
-Both techniques work with all supported version of Python.
+ ``atomic`` can be nested. In this case, when an inner block completes
+ successfully, its effects can still be rolled back if an exception is
+ raised in the outer block at a later point.
-.. _decorator: http://docs.python.org/glossary.html#term-decorator
-.. _context manager: http://docs.python.org/glossary.html#term-context-manager
+ ``atomic`` takes a ``using`` argument which should be the name of a
+ database. If this argument isn't provided, Django uses the ``"default"``
+ database.
-For maximum compatibility, all of the examples below show transactions using the
-decorator syntax, but all of the follow functions may be used as context
-managers, too.
+ ``atomic`` is usable both as a `decorator`_::
-.. note::
+ from django.db import transaction
- Although the examples below use view functions as examples, these
- decorators and context managers can be used anywhere in your code
- that you need to deal with transactions.
+ @transaction.atomic
+ def viewfunc(request):
+ # This code executes inside a transaction.
+ do_stuff()
-.. _topics-db-transactions-autocommit:
+ and as a `context manager`_::
-.. function:: autocommit
+ from django.db import transaction
+
+ def viewfunc(request):
+ # This code executes in autocommit mode (Django's default).
+ do_stuff()
- Use the ``autocommit`` decorator to switch a view function to Django's
- default commit behavior, regardless of the global transaction setting.
+ with transaction.atomic():
+ # This code executes inside a transaction.
+ do_more_stuff()
- Example::
+ .. _decorator: http://docs.python.org/glossary.html#term-decorator
+ .. _context manager: http://docs.python.org/glossary.html#term-context-manager
- from django.db import transaction
+ Wrapping ``atomic`` in a try/except block allows for natural handling of
+ integrity errors::
+
+ from django.db import IntegrityError, transaction
- @transaction.autocommit
+ @transaction.atomic
def viewfunc(request):
- ....
+ do_stuff()
- @transaction.autocommit(using="my_other_database")
- def viewfunc2(request):
- ....
+ try:
+ with transaction.atomic():
+ do_stuff_that_could_fail()
+ except IntegrityError:
+ handle_exception()
- Within ``viewfunc()``, transactions will be committed as soon as you call
- ``model.save()``, ``model.delete()``, or any other function that writes to
- the database. ``viewfunc2()`` will have this same behavior, but for the
- ``"my_other_database"`` connection.
+ do_more_stuff()
-.. function:: commit_on_success
+ In this example, even if ``do_stuff_that_could_fail()`` causes a database
+ error by breaking an integrity constraint, you can execute queries in
+ ``do_more_stuff()``, and the changes from ``do_stuff()`` are still there.
- Use the ``commit_on_success`` decorator to use a single transaction for all
- the work done in a function::
+ In order to guarantee atomicity, ``atomic`` disables some APIs. Attempting
+ to commit, roll back, or change the autocommit state of the database
+ connection within an ``atomic`` block will raise an exception.
- from django.db import transaction
+ ``atomic`` can only be used in autocommit mode. It will raise an exception
+ if autocommit is turned off.
- @transaction.commit_on_success
- def viewfunc(request):
- ....
+ Under the hood, Django's transaction management code:
- @transaction.commit_on_success(using="my_other_database")
- def viewfunc2(request):
- ....
+ - opens a transaction when entering the outermost ``atomic`` block;
+ - creates a savepoint when entering an inner ``atomic`` block;
+ - releases or rolls back to the savepoint when exiting an inner block;
+ - commits or rolls back the transaction when exiting the outermost block.
- If the function returns successfully, then Django will commit all work done
- within the function at that point. If the function raises an exception,
- though, Django will roll back the transaction.
+ You can disable the creation of savepoints for inner blocks by setting the
+ ``savepoint`` argument to ``False``. If an exception occurs, Django will
+ perform the rollback when exiting the first parent block with a savepoint
+ if there is one, and the outermost block otherwise. Atomicity is still
+ guaranteed by the outer transaction. This option should only be used if
+ the overhead of savepoints is noticeable. It has the drawback of breaking
+ the error handling described above.
-.. function:: commit_manually
+.. admonition:: Performance considerations
- Use the ``commit_manually`` decorator if you need full control over
- transactions. It tells Django you'll be managing the transaction on your
- own.
+ Open transactions have a performance cost for your database server. To
+ minimize this overhead, keep your transactions as short as possible. This
+ is especially important of you're using :func:`atomic` in long-running
+ processes, outside of Django's request / response cycle.
- Whether you are writing or simply reading from the database, you must
- ``commit()`` or ``rollback()`` explicitly or Django will raise a
- :exc:`TransactionManagementError` exception. This is required when reading
- from the database because ``SELECT`` statements may call functions which
- modify tables, and thus it is impossible to know if any data has been
- modified.
+Autocommit
+==========
- Manual transaction management looks like this::
+.. _autocommit-details:
- from django.db import transaction
+Why Django uses autocommit
+--------------------------
- @transaction.commit_manually
- def viewfunc(request):
- ...
- # You can commit/rollback however and whenever you want
- transaction.commit()
- ...
+In the SQL standards, each SQL query starts a transaction, unless one is
+already in progress. Such transactions must then be committed or rolled back.
- # But you've got to remember to do it yourself!
- try:
- ...
- except:
- transaction.rollback()
- else:
- transaction.commit()
+This isn't always convenient for application developers. To alleviate this
+problem, most databases provide an autocommit mode. When autocommit is turned
+on, each SQL query is wrapped in its own transaction. In other words, the
+transaction is not only automatically started, but also automatically
+committed.
- @transaction.commit_manually(using="my_other_database")
- def viewfunc2(request):
- ....
+:pep:`249`, the Python Database API Specification v2.0, requires autocommit to
+be initially turned off. Django overrides this default and turns autocommit
+on.
-.. _topics-db-transactions-requirements:
+To avoid this, you can :ref:`deactivate the transaction management
+<deactivate-transaction-management>`, but it isn't recommended.
-Requirements for transaction handling
-=====================================
+.. versionchanged:: 1.6
+ Before Django 1.6, autocommit was turned off, and it was emulated by
+ forcing a commit after write operations in the ORM.
-Django requires that every transaction that is opened is closed before
-the completion of a request. If you are using :func:`autocommit` (the
-default commit mode) or :func:`commit_on_success`, this will be done
-for you automatically (with the exception of :ref:`executing custom SQL
-<executing-custom-sql>`). However, if you are manually managing
-transactions (using the :func:`commit_manually` decorator), you must
-ensure that the transaction is either committed or rolled back before
-a request is completed.
+.. warning::
-This applies to all database operations, not just write operations. Even
-if your transaction only reads from the database, the transaction must
-be committed or rolled back before you complete a request.
+ If you're using the database API directly — for instance, you're running
+ SQL queries with ``cursor.execute()`` — be aware that autocommit is on,
+ and consider wrapping your operations in a transaction, with
+ :func:`atomic`, to ensure consistency.
.. _deactivate-transaction-management:
-How to globally deactivate transaction management
-=================================================
+Deactivating transaction management
+-----------------------------------
+
+You can totally disable Django's transaction management for a given database
+by setting :setting:`AUTOCOMMIT <DATABASE-AUTOCOMMIT>` to ``False`` in its
+configuration. If you do this, Django won't enable autocommit, and won't
+perform any commits. You'll get the regular behavior of the underlying
+database library.
+
+This requires you to commit explicitly every transaction, even those started
+by Django or by third-party libraries. Thus, this is best used in situations
+where you want to run your own transaction-controlling middleware or do
+something really strange.
+
+.. versionchanged:: 1.6
+ This used to be controlled by the ``TRANSACTIONS_MANAGED`` setting.
+
+Low-level APIs
+==============
+
+.. warning::
+
+ Always prefer :func:`atomic` if possible at all. It accounts for the
+ idiosyncrasies of each database and prevents invalid operations.
+
+ The low level APIs are only useful if you're implementing your own
+ transaction management.
+
+.. _managing-autocommit:
+
+Autocommit
+----------
+
+.. versionadded:: 1.6
+
+Django provides a straightforward API to manage the autocommit state of each
+database connection, if you need to.
+
+.. function:: get_autocommit(using=None)
+
+.. function:: set_autocommit(autocommit, using=None)
+
+These functions take a ``using`` argument which should be the name of a
+database. If it isn't provided, Django uses the ``"default"`` database.
+
+Autocommit is initially turned on. If you turn it off, it's your
+responsibility to restore it.
+
+Once you turn autocommit off, you get the default behavior of your database
+adapter, and Django won't help you. Although that behavior is specified in
+:pep:`249`, implementations of adapters aren't always consistent with one
+another. Review the documentation of the adapter you're using carefully.
+
+You must ensure that no transaction is active, usually by issuing a
+:func:`commit` or a :func:`rollback`, before turning autocommit back on.
+
+:func:`atomic` requires autocommit to be turned on; it will raise an exception
+if autocommit is off. Django will also refuse to turn autocommit off when an
+:func:`atomic` block is active, because that would break atomicity.
+
+Transactions
+------------
-Control freaks can totally disable all transaction management by setting
-:setting:`TRANSACTIONS_MANAGED` to ``True`` in the Django settings file.
+A transaction is an atomic set of database queries. Even if your program
+crashes, the database guarantees that either all the changes will be applied,
+or none of them.
-If you do this, Django won't provide any automatic transaction management
-whatsoever. Middleware will no longer implicitly commit transactions, and
-you'll need to roll management yourself. This even requires you to commit
-changes done by middleware somewhere else.
+Django doesn't provide an API to start a transaction. The expected way to
+start a transaction is to disable autocommit with :func:`set_autocommit`.
-Thus, this is best used in situations where you want to run your own
-transaction-controlling middleware or do something really strange. In almost
-all situations, you'll be better off using the default behavior, or the
-transaction middleware, and only modify selected functions as needed.
+Once you're in a transaction, you can choose either to apply the changes
+you've performed until this point with :func:`commit`, or to cancel them with
+:func:`rollback`.
+
+.. function:: commit(using=None)
+
+.. function:: rollback(using=None)
+
+These functions take a ``using`` argument which should be the name of a
+database. If it isn't provided, Django uses the ``"default"`` database.
+
+Django will refuse to commit or to rollback when an :func:`atomic` block is
+active, because that would break atomicity.
.. _topics-db-transactions-savepoints:
Savepoints
-==========
+----------
-A savepoint is a marker within a transaction that enables you to roll back part
-of a transaction, rather than the full transaction. Savepoints are available
-with the PostgreSQL 8, Oracle and MySQL (when using the InnoDB storage engine)
-backends. Other backends provide the savepoint functions, but they're empty
-operations -- they don't actually do anything.
+A savepoint is a marker within a transaction that enables you to roll back
+part of a transaction, rather than the full transaction. Savepoints are
+available with the SQLite (≥ 3.6.8), PostgreSQL, Oracle and MySQL (when using
+the InnoDB storage engine) backends. Other backends provide the savepoint
+functions, but they're empty operations -- they don't actually do anything.
-Savepoints aren't especially useful if you are using the default
-``autocommit`` behavior of Django. However, if you are using
-``commit_on_success`` or ``commit_manually``, each open transaction will build
-up a series of database operations, awaiting a commit or rollback. If you
-issue a rollback, the entire transaction is rolled back. Savepoints provide
-the ability to perform a fine-grained rollback, rather than the full rollback
-that would be performed by ``transaction.rollback()``.
+Savepoints aren't especially useful if you are using autocommit, the default
+behavior of Django. However, once you open a transaction with :func:`atomic`,
+you build up a series of database operations awaiting a commit or rollback. If
+you issue a rollback, the entire transaction is rolled back. Savepoints
+provide the ability to perform a fine-grained rollback, rather than the full
+rollback that would be performed by ``transaction.rollback()``.
+
+.. versionchanged:: 1.6
+
+When the :func:`atomic` decorator is nested, it creates a savepoint to allow
+partial commit or rollback. You're strongly encouraged to use :func:`atomic`
+rather than the functions described below, but they're still part of the
+public API, and there's no plan to deprecate them.
Each of these functions takes a ``using`` argument which should be the name of
a database for which the behavior applies. If no ``using`` argument is
provided then the ``"default"`` database is used.
-Savepoints are controlled by three methods on the transaction object:
+Savepoints are controlled by three functions in :mod:`django.db.transaction`:
-.. method:: transaction.savepoint(using=None)
+.. function:: savepoint(using=None)
Creates a new savepoint. This marks a point in the transaction that
is known to be in a "good" state.
- Returns the savepoint ID (sid).
+ Returns the savepoint ID (``sid``).
+
+.. function:: savepoint_commit(sid, using=None)
+
+ Releases savepoint ``sid``. The changes performed since the savepoint was
+ created become part of the transaction.
+
+.. function:: savepoint_rollback(sid, using=None)
-.. method:: transaction.savepoint_commit(sid, using=None)
+ Rolls back the transaction to savepoint ``sid``.
- Updates the savepoint to include any operations that have been performed
- since the savepoint was created, or since the last commit.
+These functions do nothing if savepoints aren't supported or if the database
+is in autocommit mode.
-.. method:: transaction.savepoint_rollback(sid, using=None)
+In addition, there's a utility function:
- Rolls the transaction back to the last point at which the savepoint was
- committed.
+.. function:: clean_savepoints(using=None)
+
+ Resets the counter used to generate unique savepoint IDs.
The following example demonstrates the use of savepoints::
from django.db import transaction
- @transaction.commit_manually
+ # open a transaction
+ @transaction.atomic
def viewfunc(request):
a.save()
- # open transaction now contains a.save()
+ # transaction now contains a.save()
+
sid = transaction.savepoint()
b.save()
- # open transaction now contains a.save() and b.save()
+ # transaction now contains a.save() and b.save()
if want_to_keep_b:
transaction.savepoint_commit(sid)
@@ -289,10 +378,25 @@ The following example demonstrates the use of savepoints::
transaction.savepoint_rollback(sid)
# open transaction now contains only a.save()
- transaction.commit()
+Database-specific notes
+=======================
+
+Savepoints in SQLite
+--------------------
+
+While SQLite ≥ 3.6.8 supports savepoints, a flaw in the design of the
+:mod:`sqlite3` makes them hardly usable.
+
+When autocommit is enabled, savepoints don't make sense. When it's disabled,
+:mod:`sqlite3` commits implicitly before savepoint-related statement. (It
+commits before any statement other than ``SELECT``, ``INSERT``, ``UPDATE``,
+``DELETE`` and ``REPLACE``.)
+
+As a consequence, savepoints are only usable inside a transaction ie. inside
+an :func:`atomic` block.
Transactions in MySQL
-=====================
+---------------------
If you're using MySQL, your tables may or may not support transactions; it
depends on your MySQL version and the table types you're using. (By
@@ -301,14 +405,14 @@ peculiarities are outside the scope of this article, but the MySQL site has
`information on MySQL transactions`_.
If your MySQL setup does *not* support transactions, then Django will function
-in auto-commit mode: Statements will be executed and committed as soon as
+in autocommit mode: Statements will be executed and committed as soon as
they're called. If your MySQL setup *does* support transactions, Django will
handle transactions as explained in this document.
.. _information on MySQL transactions: http://dev.mysql.com/doc/refman/5.0/en/sql-syntax-transactions.html
Handling exceptions within PostgreSQL transactions
-==================================================
+--------------------------------------------------
When a call to a PostgreSQL cursor raises an exception (typically
``IntegrityError``), all subsequent SQL in the same transaction will fail with
@@ -321,7 +425,7 @@ force_insert/force_update flag, or invoking custom SQL.
There are several ways to recover from this sort of error.
Transaction rollback
---------------------
+~~~~~~~~~~~~~~~~~~~~
The first option is to roll back the entire transaction. For example::
@@ -338,13 +442,13 @@ made by ``a.save()`` would be lost, even though that operation raised no error
itself.
Savepoint rollback
-------------------
+~~~~~~~~~~~~~~~~~~
-If you are using PostgreSQL 8 or later, you can use :ref:`savepoints
-<topics-db-transactions-savepoints>` to control the extent of a rollback.
-Before performing a database operation that could fail, you can set or update
-the savepoint; that way, if the operation fails, you can roll back the single
-offending operation, rather than the entire transaction. For example::
+You can use :ref:`savepoints <topics-db-transactions-savepoints>` to control
+the extent of a rollback. Before performing a database operation that could
+fail, you can set or update the savepoint; that way, if the operation fails,
+you can roll back the single offending operation, rather than the entire
+transaction. For example::
a.save() # Succeeds, and never undone by savepoint rollback
try:
@@ -358,25 +462,227 @@ offending operation, rather than the entire transaction. For example::
In this example, ``a.save()`` will not be undone in the case where
``b.save()`` raises an exception.
-Database-level autocommit
--------------------------
+.. _transactions-upgrading-from-1.5:
-With PostgreSQL 8.2 or later, there is an advanced option to run PostgreSQL
-with :doc:`database-level autocommit </ref/databases>`. If you use this option,
-there is no constantly open transaction, so it is always possible to continue
-after catching an exception. For example::
+Changes from Django 1.5 and earlier
+===================================
+
+The features described below were deprecated in Django 1.6 and will be removed
+in Django 1.8. They're documented in order to ease the migration to the new
+transaction management APIs.
+
+Legacy APIs
+-----------
+
+The following functions, defined in ``django.db.transaction``, provided a way
+to control transactions on a per-function or per-code-block basis. They could
+be used as decorators or as context managers, and they accepted a ``using``
+argument, exactly like :func:`atomic`.
+
+.. function:: autocommit
+
+ Enable Django's default autocommit behavior.
+
+ Transactions will be committed as soon as you call ``model.save()``,
+ ``model.delete()``, or any other function that writes to the database.
+
+.. function:: commit_on_success
+
+ Use a single transaction for all the work done in a function.
+
+ If the function returns successfully, then Django will commit all work done
+ within the function at that point. If the function raises an exception,
+ though, Django will roll back the transaction.
+
+.. function:: commit_manually
+
+ Tells Django you'll be managing the transaction on your own.
+
+ Whether you are writing or simply reading from the database, you must
+ ``commit()`` or ``rollback()`` explicitly or Django will raise a
+ :exc:`TransactionManagementError` exception. This is required when reading
+ from the database because ``SELECT`` statements may call functions which
+ modify tables, and thus it is impossible to know if any data has been
+ modified.
+
+.. _transaction-states:
+
+Transaction states
+------------------
+
+The three functions described above relied on a concept called "transaction
+states". This mechanisme was deprecated in Django 1.6, but it's still
+available until Django 1.8..
+
+At any time, each database connection is in one of these two states:
+
+- **auto mode**: autocommit is enabled;
+- **managed mode**: autocommit is disabled.
+
+Django starts in auto mode. ``TransactionMiddleware``,
+:func:`commit_on_success` and :func:`commit_manually` activate managed mode;
+:func:`autocommit` activates auto mode.
+
+Internally, Django keeps a stack of states. Activations and deactivations must
+be balanced.
+
+For example, ``commit_on_success`` switches to managed mode when entering the
+block of code it controls; when exiting the block, it commits or rollbacks,
+and switches back to auto mode.
+
+So :func:`commit_on_success` really has two effects: it changes the
+transaction state and it defines an transaction block. Nesting will give the
+expected results in terms of transaction state, but not in terms of
+transaction semantics. Most often, the inner block will commit, breaking the
+atomicity of the outer block.
+
+:func:`autocommit` and :func:`commit_manually` have similar limitations.
+
+API changes
+-----------
+
+Transaction middleware
+~~~~~~~~~~~~~~~~~~~~~~
+
+In Django 1.6, ``TransactionMiddleware`` is deprecated and replaced
+:setting:`ATOMIC_REQUESTS <DATABASE-ATOMIC_REQUESTS>`. While the general
+behavior is the same, there are a few differences.
+
+With the transaction middleware, it was still possible to switch to autocommit
+or to commit explicitly in a view. Since :func:`atomic` guarantees atomicity,
+this isn't allowed any longer.
- a.save() # succeeds
+To avoid wrapping a particular view in a transaction, instead of::
+
+ @transaction.autocommit
+ def my_view(request):
+ do_stuff()
+
+you must now use this pattern::
+
+ def my_view(request):
+ do_stuff()
+ my_view.transactions_per_request = False
+
+The transaction middleware applied not only to view functions, but also to
+middleware modules that come after it. For instance, if you used the session
+middleware after the transaction middleware, session creation was part of the
+transaction. :setting:`ATOMIC_REQUESTS <DATABASE-ATOMIC_REQUESTS>` only
+applies to the view itself.
+
+Managing transactions
+~~~~~~~~~~~~~~~~~~~~~
+
+Starting with Django 1.6, :func:`atomic` is the only supported API for
+defining a transaction. Unlike the deprecated APIs, it's nestable and always
+guarantees atomicity.
+
+In most cases, it will be a drop-in replacement for :func:`commit_on_success`.
+
+During the deprecation period, it's possible to use :func:`atomic` within
+:func:`autocommit`, :func:`commit_on_success` or :func:`commit_manually`.
+However, the reverse is forbidden, because nesting the old decorators /
+context managers breaks atomicity.
+
+If you enter :func:`atomic` while you're in managed mode, it will trigger a
+commit to start from a clean slate.
+
+Managing autocommit
+~~~~~~~~~~~~~~~~~~~
+
+Django 1.6 introduces an explicit :ref:`API for mananging autocommit
+<managing-autocommit>`.
+
+To disable autocommit temporarily, instead of::
+
+ with transaction.commit_manually():
+ # do stuff
+
+you should now use::
+
+ transaction.set_autocommit(False)
try:
- b.save() # Could throw exception
- except IntegrityError:
- pass
- c.save() # succeeds
+ # do stuff
+ finally:
+ transaction.set_autocommit(True)
+
+To enable autocommit temporarily, instead of::
+
+ with transaction.autocommit():
+ # do stuff
+
+you should now use::
+
+ transaction.set_autocommit(True)
+ try:
+ # do stuff
+ finally:
+ transaction.set_autocommit(False)
+
+Disabling transaction management
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Instead of setting ``TRANSACTIONS_MANAGED = True``, set the ``AUTOCOMMIT`` key
+to ``False`` in the configuration of each database, as explained in :ref
+:`deactivate-transaction-management`.
+
+Backwards incompatibilities
+---------------------------
+
+Since version 1.6, Django uses database-level autocommit in auto mode.
+Previously, it implemented application-level autocommit by triggering a commit
+after each ORM write.
+
+As a consequence, each database query (for instance, an ORM read) started a
+transaction that lasted until the next ORM write. Such "automatic
+transactions" no longer exist in Django 1.6.
+
+There are four known scenarios where this is backwards-incompatible.
+
+Note that managed mode isn't affected at all. This section assumes auto mode.
+See the :ref:`description of modes <transaction-states>` above.
+
+Sequences of custom SQL queries
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you're executing several :ref:`custom SQL queries <executing-custom-sql>`
+in a row, each one now runs in its own transaction, instead of sharing the
+same "automatic transaction". If you need to enforce atomicity, you must wrap
+the sequence of queries in :func:`commit_on_success`.
+
+To check for this problem, look for calls to ``cursor.execute()``. They're
+usually followed by a call to ``transaction.commit_unless_managed``, which
+isn't necessary any more and should be removed.
+
+Select for update
+~~~~~~~~~~~~~~~~~
+
+If you were relying on "automatic transactions" to provide locking between
+:meth:`~django.db.models.query.QuerySet.select_for_update` and a subsequent
+write operation — an extremely fragile design, but nonetheless possible — you
+must wrap the relevant code in :func:`atomic`.
+
+Using a high isolation level
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If you were using the "repeatable read" isolation level or higher, and if you
+relied on "automatic transactions" to guarantee consistency between successive
+reads, the new behavior might be backwards-incompatible. To enforce
+consistency, you must wrap such sequences in :func:`atomic`.
+
+MySQL defaults to "repeatable read" and SQLite to "serializable"; they may be
+affected by this problem.
+
+At the "read committed" isolation level or lower, "automatic transactions"
+have no effect on the semantics of any sequence of ORM operations.
+
+PostgreSQL and Oracle default to "read committed" and aren't affected, unless
+you changed the isolation level.
-.. note::
+Using unsupported database features
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- This is not the same as the :ref:`autocommit decorator
- <topics-db-transactions-autocommit>`. When using database level autocommit
- there is no database transaction at all. The ``autocommit`` decorator
- still uses transactions, automatically committing each transaction when
- a database modifying operation occurs.
+With triggers, views, or functions, it's possible to make ORM reads result in
+database modifications. Django 1.5 and earlier doesn't deal with this case and
+it's theoretically possible to observe a different behavior after upgrading to
+Django 1.6 or later. In doubt, use :func:`atomic` to enforce integrity.