mirror of
https://github.com/django/django.git
synced 2024-12-22 17:16:24 +00:00
Fixed #35712 -- Prevented Q.check() from leaving the connection in an unusable state.
Co-authored-by: Simon Charette <charette.s@gmail.com>
This commit is contained in:
parent
387475c5b2
commit
c6a4f853c7
@ -10,9 +10,10 @@ import functools
|
|||||||
import inspect
|
import inspect
|
||||||
import logging
|
import logging
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
from contextlib import nullcontext
|
||||||
|
|
||||||
from django.core.exceptions import FieldError
|
from django.core.exceptions import FieldError
|
||||||
from django.db import DEFAULT_DB_ALIAS, DatabaseError, connections
|
from django.db import DEFAULT_DB_ALIAS, DatabaseError, connections, transaction
|
||||||
from django.db.models.constants import LOOKUP_SEP
|
from django.db.models.constants import LOOKUP_SEP
|
||||||
from django.utils import tree
|
from django.utils import tree
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
@ -130,14 +131,21 @@ class Q(tree.Node):
|
|||||||
value = Value(value)
|
value = Value(value)
|
||||||
query.add_annotation(value, name, select=False)
|
query.add_annotation(value, name, select=False)
|
||||||
query.add_annotation(Value(1), "_check")
|
query.add_annotation(Value(1), "_check")
|
||||||
|
connection = connections[using]
|
||||||
# This will raise a FieldError if a field is missing in "against".
|
# This will raise a FieldError if a field is missing in "against".
|
||||||
if connections[using].features.supports_comparing_boolean_expr:
|
if connection.features.supports_comparing_boolean_expr:
|
||||||
query.add_q(Q(Coalesce(self, True, output_field=BooleanField())))
|
query.add_q(Q(Coalesce(self, True, output_field=BooleanField())))
|
||||||
else:
|
else:
|
||||||
query.add_q(self)
|
query.add_q(self)
|
||||||
compiler = query.get_compiler(using=using)
|
compiler = query.get_compiler(using=using)
|
||||||
|
context_manager = (
|
||||||
|
transaction.atomic(using=using)
|
||||||
|
if connection.in_atomic_block
|
||||||
|
else nullcontext()
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
return compiler.execute_sql(SINGLE) is not None
|
with context_manager:
|
||||||
|
return compiler.execute_sql(SINGLE) is not None
|
||||||
except DatabaseError as e:
|
except DatabaseError as e:
|
||||||
logger.warning("Got a database error calling check() on %r: %s", self, e)
|
logger.warning("Got a database error calling check() on %r: %s", self, e)
|
||||||
return True
|
return True
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
from django.core.exceptions import FieldError
|
from django.core.exceptions import FieldError
|
||||||
|
from django.db import connection
|
||||||
from django.db.models import (
|
from django.db.models import (
|
||||||
BooleanField,
|
BooleanField,
|
||||||
Exists,
|
Exists,
|
||||||
@ -327,3 +328,6 @@ class QCheckTests(TestCase):
|
|||||||
f"Got a database error calling check() on {q!r}: ",
|
f"Got a database error calling check() on {q!r}: ",
|
||||||
cm.records[0].getMessage(),
|
cm.records[0].getMessage(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# We must leave the connection in a usable state (#35712).
|
||||||
|
self.assertTrue(connection.is_usable())
|
||||||
|
Loading…
Reference in New Issue
Block a user