Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions django/db/transaction.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import warnings
from contextlib import ContextDecorator, contextmanager
from functools import wraps

from django.db import (
DEFAULT_DB_ALIAS,
Expand Down Expand Up @@ -337,10 +338,16 @@ def atomic(using=None, savepoint=True, durable=False):

def _non_atomic_requests(view, using):
try:
view._non_atomic_requests.add(using)
databases = view._non_atomic_requests | {using}
except AttributeError:
view._non_atomic_requests = {using}
return view
databases = {using}

@wraps(view)
def wrapper(*args, **kwargs):
return view(*args, **kwargs)

wrapper._non_atomic_requests = databases
return wrapper


def non_atomic_requests(using=None):
Expand Down
2 changes: 1 addition & 1 deletion docs/ref/models/querysets.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2542,7 +2542,7 @@ them, but it has a few caveats:
batch_size = 100
ids_iter = iter(range(1000))
while ids := list(islice(ids_iter, batch_size)):
batch = Entry.objects.filter(ids__in=ids)
batch = Entry.objects.filter(id__in=ids)
for entry in batch:
entry.headline = f"Updated headline {entry.pk}"
Entry.objects.bulk_update(batch, ["headline"], batch_size=batch_size)
Expand Down
14 changes: 13 additions & 1 deletion tests/handlers/tests.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from django.core.exceptions import ImproperlyConfigured
from django.core.handlers.wsgi import WSGIHandler, WSGIRequest, get_script_name
from django.core.signals import request_finished, request_started
from django.db import close_old_connections, connection
from django.db import close_old_connections, connection, transaction
from django.http import HttpResponse
from django.test import (
AsyncRequestFactory,
RequestFactory,
Expand Down Expand Up @@ -143,6 +144,17 @@ def test_no_auto_transaction(self):
# The non_atomic_requests decorator is used for an incorrect table.
self.assertContains(response, "True")

def test_non_atomic_requests_does_not_mutate_original(self):
def my_view(request):
return HttpResponse("Ok")

wrapped_once = transaction.non_atomic_requests(using="default")(my_view)
wrapped_twice = transaction.non_atomic_requests(using="other")(wrapped_once)

self.assertIsNot(wrapped_twice, wrapped_once)
self.assertEqual(wrapped_once._non_atomic_requests, {"default"})
self.assertEqual(wrapped_twice._non_atomic_requests, {"default", "other"})


@override_settings(ROOT_URLCONF="handlers.urls")
class SignalsTests(SimpleTestCase):
Expand Down
Loading