mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Fixed #34060 -- Fixed migrations crash when adding check constraints with JSONField __exact lookup on Oracle.
This commit is contained in:
		
				
					committed by
					
						
						Mariusz Felisiak
					
				
			
			
				
	
			
			
			
						parent
						
							22285d366c
						
					
				
				
					commit
					c991602ce5
				
			@@ -347,9 +347,10 @@ END;
 | 
				
			|||||||
    def lookup_cast(self, lookup_type, internal_type=None):
 | 
					    def lookup_cast(self, lookup_type, internal_type=None):
 | 
				
			||||||
        if lookup_type in ("iexact", "icontains", "istartswith", "iendswith"):
 | 
					        if lookup_type in ("iexact", "icontains", "istartswith", "iendswith"):
 | 
				
			||||||
            return "UPPER(%s)"
 | 
					            return "UPPER(%s)"
 | 
				
			||||||
        if (
 | 
					        if lookup_type != "isnull" and internal_type in (
 | 
				
			||||||
            lookup_type != "isnull" and internal_type in ("BinaryField", "TextField")
 | 
					            "BinaryField",
 | 
				
			||||||
        ) or (lookup_type == "exact" and internal_type == "JSONField"):
 | 
					            "TextField",
 | 
				
			||||||
 | 
					        ):
 | 
				
			||||||
            return "DBMS_LOB.SUBSTR(%s)"
 | 
					            return "DBMS_LOB.SUBSTR(%s)"
 | 
				
			||||||
        return "%s"
 | 
					        return "%s"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -106,6 +106,13 @@ class DatabaseFeatures(BaseDatabaseFeatures):
 | 
				
			|||||||
                    "test_group_by_nested_expression_with_params",
 | 
					                    "test_group_by_nested_expression_with_params",
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					        if not is_psycopg3:
 | 
				
			||||||
 | 
					            expected_failures.update(
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    "constraints.tests.CheckConstraintTests."
 | 
				
			||||||
 | 
					                    "test_validate_jsonfield_exact",
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
        return expected_failures
 | 
					        return expected_failures
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @cached_property
 | 
					    @cached_property
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -310,6 +310,11 @@ class JSONExact(lookups.Exact):
 | 
				
			|||||||
            rhs %= tuple(func)
 | 
					            rhs %= tuple(func)
 | 
				
			||||||
        return rhs, rhs_params
 | 
					        return rhs, rhs_params
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def as_oracle(self, compiler, connection):
 | 
				
			||||||
 | 
					        lhs, lhs_params = self.process_lhs(compiler, connection)
 | 
				
			||||||
 | 
					        rhs, rhs_params = self.process_rhs(compiler, connection)
 | 
				
			||||||
 | 
					        return f"JSON_EQUAL({lhs}, {rhs})", (*lhs_params, *rhs_params)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class JSONIContains(CaseInsensitiveMixin, lookups.IContains):
 | 
					class JSONIContains(CaseInsensitiveMixin, lookups.IContains):
 | 
				
			||||||
    pass
 | 
					    pass
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -365,6 +365,20 @@ class CheckConstraintTests(TestCase):
 | 
				
			|||||||
            constraint_with_pk.validate(ChildModel, ChildModel(id=1, age=1))
 | 
					            constraint_with_pk.validate(ChildModel, ChildModel(id=1, age=1))
 | 
				
			||||||
        constraint_with_pk.validate(ChildModel, ChildModel(pk=1, age=1), exclude={"pk"})
 | 
					        constraint_with_pk.validate(ChildModel, ChildModel(pk=1, age=1), exclude={"pk"})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @skipUnlessDBFeature("supports_json_field")
 | 
				
			||||||
 | 
					    def test_validate_jsonfield_exact(self):
 | 
				
			||||||
 | 
					        data = {"release": "5.0.2", "version": "stable"}
 | 
				
			||||||
 | 
					        json_exact_constraint = models.CheckConstraint(
 | 
				
			||||||
 | 
					            check=models.Q(data__version="stable"),
 | 
				
			||||||
 | 
					            name="only_stable_version",
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        json_exact_constraint.validate(JSONFieldModel, JSONFieldModel(data=data))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        data = {"release": "5.0.2", "version": "not stable"}
 | 
				
			||||||
 | 
					        msg = f"Constraint “{json_exact_constraint.name}” is violated."
 | 
				
			||||||
 | 
					        with self.assertRaisesMessage(ValidationError, msg):
 | 
				
			||||||
 | 
					            json_exact_constraint.validate(JSONFieldModel, JSONFieldModel(data=data))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class UniqueConstraintTests(TestCase):
 | 
					class UniqueConstraintTests(TestCase):
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2803,6 +2803,40 @@ class SchemaTests(TransactionTestCase):
 | 
				
			|||||||
            DurationModel.objects.create(duration=datetime.timedelta(minutes=4))
 | 
					            DurationModel.objects.create(duration=datetime.timedelta(minutes=4))
 | 
				
			||||||
        DurationModel.objects.create(duration=datetime.timedelta(minutes=10))
 | 
					        DurationModel.objects.create(duration=datetime.timedelta(minutes=10))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @skipUnlessDBFeature(
 | 
				
			||||||
 | 
					        "supports_column_check_constraints",
 | 
				
			||||||
 | 
					        "can_introspect_check_constraints",
 | 
				
			||||||
 | 
					        "supports_json_field",
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    @isolate_apps("schema")
 | 
				
			||||||
 | 
					    def test_check_constraint_exact_jsonfield(self):
 | 
				
			||||||
 | 
					        class JSONConstraintModel(Model):
 | 
				
			||||||
 | 
					            data = JSONField()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            class Meta:
 | 
				
			||||||
 | 
					                app_label = "schema"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        with connection.schema_editor() as editor:
 | 
				
			||||||
 | 
					            editor.create_model(JSONConstraintModel)
 | 
				
			||||||
 | 
					        self.isolated_local_models = [JSONConstraintModel]
 | 
				
			||||||
 | 
					        constraint_name = "check_only_stable_version"
 | 
				
			||||||
 | 
					        constraint = CheckConstraint(
 | 
				
			||||||
 | 
					            check=Q(data__version="stable"),
 | 
				
			||||||
 | 
					            name=constraint_name,
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        JSONConstraintModel._meta.constraints = [constraint]
 | 
				
			||||||
 | 
					        with connection.schema_editor() as editor:
 | 
				
			||||||
 | 
					            editor.add_constraint(JSONConstraintModel, constraint)
 | 
				
			||||||
 | 
					        constraints = self.get_constraints(JSONConstraintModel._meta.db_table)
 | 
				
			||||||
 | 
					        self.assertIn(constraint_name, constraints)
 | 
				
			||||||
 | 
					        with self.assertRaises(IntegrityError), atomic():
 | 
				
			||||||
 | 
					            JSONConstraintModel.objects.create(
 | 
				
			||||||
 | 
					                data={"release": "5.0.2dev", "version": "dev"}
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        JSONConstraintModel.objects.create(
 | 
				
			||||||
 | 
					            data={"release": "5.0.3", "version": "stable"}
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @skipUnlessDBFeature(
 | 
					    @skipUnlessDBFeature(
 | 
				
			||||||
        "supports_column_check_constraints", "can_introspect_check_constraints"
 | 
					        "supports_column_check_constraints", "can_introspect_check_constraints"
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user