#36222: ExclusionConstraint.validate() crashes when exclude includes a field in
condition.
-------------------------------------+-------------------------------------
Reporter: Clifford Gama | Type: Bug
Status: new | Component: Database
| layer (models, ORM)
Version: dev | Severity: Normal
Keywords: | Triage Stage:
validate_constraints | Unreviewed
ExclusionConstraint exclude |
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Discovered during work on #35676.
Failing test:
{{{#!diff
diff --git a/tests/postgres_tests/test_constraints.py
b/tests/postgres_tests/test_constraints.py
index ab5bf2bab1..ae02fa22ff 100644
--- a/tests/postgres_tests/test_constraints.py
+++ b/tests/postgres_tests/test_constraints.py
@@ -797,6 +797,17 @@ class ExclusionConstraintTests(PostgreSQLTestCase):
),
exclude={"datespan", "start", "end", "room"},
)
+ # Excluded condition field.
+ constraint.validate(
+ HotelReservation,
+ HotelReservation(
+ datespan=(datetimes[1].date(), datetimes[2].date()),
+ start=datetimes[1],
+ end=datetimes[2],
+ room=room102,
+ ),
+ exclude={"cancelled"},
+ )
def test_range_overlaps_custom(self):
class TsTzRange(Func):
}}}
Results in two test failures. Here is the failure for one of the tests:
{{{#!python
======================================================================
ERROR: test_range_overlaps
(postgres_tests.test_constraints.ExclusionConstraintTests.test_range_overlaps)
----------------------------------------------------------------------
Traceback (most recent call last):
File
"/home/clifford/code/django/tests/postgres_tests/test_constraints.py",
line 839, in test_range_overlaps
self._test_range_overlaps(constraint)
File
"/home/clifford/code/django/tests/postgres_tests/test_constraints.py",
line 801, in _test_range_overlaps
constraint.validate(
File
"/home/clifford/code/django/django/contrib/postgres/constraints.py", line
209, in validate
if (self.condition & Exists(queryset.filter(self.condition))).check(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/clifford/code/django/django/db/models/query_utils.py", line
137, in check
query.add_q(Q(Coalesce(self, True, output_field=BooleanField())))
File "/home/clifford/code/django/django/db/models/sql/query.py", line
1637, in add_q
clause, _ = self._add_q(q_object, can_reuse)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/clifford/code/django/django/db/models/sql/query.py", line
1669, in _add_q
child_clause, needed_inner = self.build_filter(
^^^^^^^^^^^^^^^^^^
File "/home/clifford/code/django/django/db/models/sql/query.py", line
1508, in build_filter
condition = filter_expr.resolve_expression(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/clifford/code/django/django/db/models/expressions.py", line
300, in resolve_expression
expr.resolve_expression(query, allow_joins, reuse, summarize)
File "/home/clifford/code/django/django/db/models/query_utils.py", line
91, in resolve_expression
clause, joins = query._add_q(
^^^^^^^^^^^^^
File "/home/clifford/code/django/django/db/models/sql/query.py", line
1669, in _add_q
child_clause, needed_inner = self.build_filter(
^^^^^^^^^^^^^^^^^^
File "/home/clifford/code/django/django/db/models/sql/query.py", line
1517, in build_filter
lookups, parts, reffed_expression = self.solve_lookup_type(arg,
summarize)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/clifford/code/django/django/db/models/sql/query.py", line
1324, in solve_lookup_type
_, field, _, lookup_parts = self.names_to_path(lookup_splitted,
self.get_meta())
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/clifford/code/django/django/db/models/sql/query.py", line
1796, in names_to_path
raise FieldError(
django.core.exceptions.FieldError: Cannot resolve keyword 'cancelled' into
field. Choices are: _check
}}}
This works correctly for `UniqueConstraint` (see
[
https://github.com/django/django/blob/fc303551077c3e023fe4f9d01fc1b3026c816fa4/tests/constraints/tests.py#L1097
test]), but has been untested (or failure has been undocumented) for
`ExclusionConstraint` since `Constraint` validation was added by #30581.
--
Ticket URL: <
https://code.djangoproject.com/ticket/36222>
Django <
https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.