Changed API to disable ATOMIC_REQUESTS per view.
A decorator is easier to apply to CBVs. Backwards compatibility isn't an issue here, except for people running on a recent clone of master. Fixed a few minor problems in the transactions docs while I was there.
This commit is contained in:
parent
bdde7feb26
commit
6633eeb886
|
@ -66,10 +66,11 @@ class BaseHandler(object):
|
|||
self._request_middleware = request_middleware
|
||||
|
||||
def make_view_atomic(self, view):
|
||||
if getattr(view, 'transactions_per_request', True):
|
||||
for db in connections.all():
|
||||
if db.settings_dict['ATOMIC_REQUESTS']:
|
||||
view = transaction.atomic(using=db.alias)(view)
|
||||
non_atomic_requests = getattr(view, '_non_atomic_requests', set())
|
||||
for db in connections.all():
|
||||
if (db.settings_dict['ATOMIC_REQUESTS']
|
||||
and db.alias not in non_atomic_requests):
|
||||
view = transaction.atomic(using=db.alias)(view)
|
||||
return view
|
||||
|
||||
def get_response(self, request):
|
||||
|
|
|
@ -333,6 +333,23 @@ def atomic(using=None, savepoint=True):
|
|||
return Atomic(using, savepoint)
|
||||
|
||||
|
||||
def _non_atomic_requests(view, using):
|
||||
try:
|
||||
view._non_atomic_requests.add(using)
|
||||
except AttributeError:
|
||||
view._non_atomic_requests = set([using])
|
||||
return view
|
||||
|
||||
|
||||
def non_atomic_requests(using=None):
|
||||
if callable(using):
|
||||
return _non_atomic_requests(using, DEFAULT_DB_ALIAS)
|
||||
else:
|
||||
if using is None:
|
||||
using = DEFAULT_DB_ALIAS
|
||||
return lambda view: _non_atomic_requests(view, using)
|
||||
|
||||
|
||||
############################################
|
||||
# Deprecated decorators / context managers #
|
||||
############################################
|
||||
|
|
|
@ -45,14 +45,6 @@ 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.
|
||||
|
||||
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::
|
||||
|
||||
def my_view(request):
|
||||
do_stuff()
|
||||
my_view.transactions_per_request = False
|
||||
|
||||
.. warning::
|
||||
|
||||
While the simplicity of this transaction model is appealing, it also makes it
|
||||
|
@ -78,6 +70,26 @@ Note that only the execution of your view is enclosed in the transactions.
|
|||
Middleware runs outside of the transaction, and so does the rendering of
|
||||
template responses.
|
||||
|
||||
When :setting:`ATOMIC_REQUESTS <DATABASE-ATOMIC_REQUESTS>` is enabled, it's
|
||||
still possible to prevent views from running in a transaction.
|
||||
|
||||
.. function:: non_atomic_requests(using=None)
|
||||
|
||||
This decorator will negate the effect of :setting:`ATOMIC_REQUESTS
|
||||
<DATABASE-ATOMIC_REQUESTS>` for a given view::
|
||||
|
||||
from django.db import transaction
|
||||
|
||||
@transaction.non_atomic_requests
|
||||
def my_view(request):
|
||||
do_stuff()
|
||||
|
||||
@transaction.non_atomic_requests(using='other')
|
||||
def my_other_view(request):
|
||||
do_stuff_on_the_other_database()
|
||||
|
||||
It only works if it's applied to the view itself.
|
||||
|
||||
.. versionchanged:: 1.6
|
||||
|
||||
Django used to provide this feature via ``TransactionMiddleware``, which is
|
||||
|
@ -519,8 +531,8 @@ 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.
|
||||
states". This mechanism 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:
|
||||
|
||||
|
@ -554,23 +566,14 @@ 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.
|
||||
behavior is the same, there are two 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.
|
||||
|
||||
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
|
||||
With the previous API, it was possible to switch to autocommit or to commit
|
||||
explicitly anywhere inside a view. Since :setting:`ATOMIC_REQUESTS
|
||||
<DATABASE-ATOMIC_REQUESTS>` relies on :func:`atomic` which enforces atomicity,
|
||||
this isn't allowed any longer. However, at the toplevel, it's still possible
|
||||
to avoid wrapping an entire view in a transaction. To achieve this, decorate
|
||||
the view with :func:`non_atomic_requests` instead of :func:`autocommit`.
|
||||
|
||||
The transaction middleware applied not only to view functions, but also to
|
||||
middleware modules that came after it. For instance, if you used the session
|
||||
|
@ -624,6 +627,9 @@ you should now use::
|
|||
finally:
|
||||
transaction.set_autocommit(False)
|
||||
|
||||
Unless you're implementing a transaction management framework, you shouldn't
|
||||
ever need to do this.
|
||||
|
||||
Disabling transaction management
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -653,7 +659,7 @@ 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`.
|
||||
the sequence of queries in :func:`atomic`.
|
||||
|
||||
To check for this problem, look for calls to ``cursor.execute()``. They're
|
||||
usually followed by a call to ``transaction.commit_unless_managed()``, which
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import connection
|
||||
from django.db import connection, transaction
|
||||
from django.http import HttpResponse, StreamingHttpResponse
|
||||
|
||||
def regular(request):
|
||||
|
@ -12,6 +12,6 @@ def streaming(request):
|
|||
def in_transaction(request):
|
||||
return HttpResponse(str(connection.in_atomic_block))
|
||||
|
||||
@transaction.non_atomic_requests
|
||||
def not_in_transaction(request):
|
||||
return HttpResponse(str(connection.in_atomic_block))
|
||||
not_in_transaction.transactions_per_request = False
|
||||
|
|
Loading…
Reference in New Issue