浏览代码

Fixed #32858 -- Fixed ExclusionConstraint crash with index transforms in expressions.

Lucidiot 3 年之前
父节点
当前提交
b69b0c3fe8
共有 3 个文件被更改,包括 20 次插入1 次删除
  1. 1 0
      AUTHORS
  2. 3 0
      django/contrib/postgres/constraints.py
  3. 16 1
      tests/postgres_tests/test_constraints.py

+ 1 - 0
AUTHORS

@@ -561,6 +561,7 @@ answer newbie questions, and generally made Django that much better:
     Luan Pablo <luanpab@gmail.com>
     Lucas Connors <https://www.revolutiontech.ca/>
     Luciano Ramalho
+    Lucidiot <lucidiot@brainshit.fr>
     Ludvig Ericson <ludvig.ericson@gmail.com>
     Luis C. Berrocal <luis.berrocal.1942@gmail.com>
     Łukasz Langa <lukasz@langa.pl>

+ 3 - 0
django/contrib/postgres/constraints.py

@@ -2,6 +2,7 @@ from django.db import NotSupportedError
 from django.db.backends.ddl_references import Statement, Table
 from django.db.models import Deferrable, F, Q
 from django.db.models.constraints import BaseConstraint
+from django.db.models.expressions import Col
 from django.db.models.sql import Query
 
 __all__ = ['ExclusionConstraint']
@@ -73,6 +74,8 @@ class ExclusionConstraint(BaseConstraint):
                 expression = F(expression)
             expression = expression.resolve_expression(query=query)
             sql, params = compiler.compile(expression)
+            if not isinstance(expression, Col):
+                sql = f'({sql})'
             try:
                 opclass = self.opclasses[idx]
                 if opclass:

+ 16 - 1
tests/postgres_tests/test_constraints.py

@@ -14,7 +14,9 @@ from django.test import modify_settings, skipUnlessDBFeature
 from django.utils import timezone
 
 from . import PostgreSQLTestCase
-from .models import HotelReservation, RangesModel, Room, Scene
+from .models import (
+    HotelReservation, IntegerArrayModel, RangesModel, Room, Scene,
+)
 
 try:
     from psycopg2.extras import DateRange, NumericRange
@@ -670,6 +672,19 @@ class ExclusionConstraintTests(PostgreSQLTestCase):
             self.get_constraints(HotelReservation._meta.db_table),
         )
 
+    def test_index_transform(self):
+        constraint_name = 'first_index_equal'
+        constraint = ExclusionConstraint(
+            name=constraint_name,
+            expressions=[('field__0', RangeOperators.EQUAL)],
+        )
+        with connection.schema_editor() as editor:
+            editor.add_constraint(IntegerArrayModel, constraint)
+        self.assertIn(
+            constraint_name,
+            self.get_constraints(IntegerArrayModel._meta.db_table),
+        )
+
     def test_range_adjacent_initially_deferred(self):
         constraint_name = 'ints_adjacent_deferred'
         self.assertNotIn(constraint_name, self.get_constraints(RangesModel._meta.db_table))