mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Fixed #33335 -- Made model validation ignore functional unique constraints.
Regression in 3aa545281e.
Thanks Hervé Le Roy for the report.
			
			
This commit is contained in:
		
				
					committed by
					
						 Mariusz Felisiak
						Mariusz Felisiak
					
				
			
			
				
	
			
			
			
						parent
						
							d3a64bea51
						
					
				
				
					commit
					1eaf38fa87
				
			| @@ -866,7 +866,11 @@ class Options: | ||||
|         return [ | ||||
|             constraint | ||||
|             for constraint in self.constraints | ||||
|             if isinstance(constraint, UniqueConstraint) and constraint.condition is None | ||||
|             if ( | ||||
|                 isinstance(constraint, UniqueConstraint) and | ||||
|                 constraint.condition is None and | ||||
|                 not constraint.contains_expressions | ||||
|             ) | ||||
|         ] | ||||
|  | ||||
|     @cached_property | ||||
|   | ||||
| @@ -35,10 +35,12 @@ option. | ||||
|     not raise ``ValidationError``\s. Rather you'll get a database integrity | ||||
|     error on ``save()``. ``UniqueConstraint``\s without a | ||||
|     :attr:`~UniqueConstraint.condition` (i.e. non-partial unique constraints) | ||||
|     are different in this regard, in that they leverage the existing | ||||
|     ``validate_unique()`` logic, and thus enable two-stage validation. In | ||||
|     addition to ``IntegrityError`` on ``save()``, ``ValidationError`` is also | ||||
|     raised during model validation when the ``UniqueConstraint`` is violated. | ||||
|     and :attr:`~UniqueConstraint.expressions` (i.e. non-functional unique | ||||
|     constraints) are different in this regard, in that they leverage the | ||||
|     existing ``validate_unique()`` logic, and thus enable two-stage validation. | ||||
|     In addition to ``IntegrityError`` on ``save()``, ``ValidationError`` is | ||||
|     also raised during model validation when the ``UniqueConstraint`` is | ||||
|     violated. | ||||
|  | ||||
| ``CheckConstraint`` | ||||
| =================== | ||||
|   | ||||
| @@ -2,6 +2,7 @@ from datetime import datetime | ||||
|  | ||||
| from django.core.exceptions import ValidationError | ||||
| from django.db import models | ||||
| from django.db.models.functions import Lower | ||||
|  | ||||
|  | ||||
| def validate_answer_to_universe(value): | ||||
| @@ -125,3 +126,13 @@ class GenericIPAddressTestModel(models.Model): | ||||
|  | ||||
| class GenericIPAddrUnpackUniqueTest(models.Model): | ||||
|     generic_v4unpack_ip = models.GenericIPAddressField(null=True, blank=True, unique=True, unpack_ipv4=True) | ||||
|  | ||||
|  | ||||
| class UniqueFuncConstraintModel(models.Model): | ||||
|     field = models.CharField(max_length=255) | ||||
|  | ||||
|     class Meta: | ||||
|         required_db_features = {'supports_expression_indexes'} | ||||
|         constraints = [ | ||||
|             models.UniqueConstraint(Lower('field'), name='func_lower_field_uq'), | ||||
|         ] | ||||
|   | ||||
| @@ -8,7 +8,8 @@ from django.test import TestCase | ||||
|  | ||||
| from .models import ( | ||||
|     CustomPKModel, FlexibleDatePost, ModelToValidate, Post, UniqueErrorsModel, | ||||
|     UniqueFieldsModel, UniqueForDateModel, UniqueTogetherModel, | ||||
|     UniqueFieldsModel, UniqueForDateModel, UniqueFuncConstraintModel, | ||||
|     UniqueTogetherModel, | ||||
| ) | ||||
|  | ||||
|  | ||||
| @@ -86,6 +87,13 @@ class GetUniqueCheckTests(unittest.TestCase): | ||||
|         ), m._get_unique_checks(exclude='start_date') | ||||
|         ) | ||||
|  | ||||
|     def test_func_unique_constraint_ignored(self): | ||||
|         m = UniqueFuncConstraintModel() | ||||
|         self.assertEqual( | ||||
|             m._get_unique_checks(), | ||||
|             ([(UniqueFuncConstraintModel, ('id',))], []), | ||||
|         ) | ||||
|  | ||||
|  | ||||
| class PerformUniqueChecksTest(TestCase): | ||||
|     def test_primary_key_unique_check_not_performed_when_adding_and_pk_not_specified(self): | ||||
| @@ -108,6 +116,10 @@ class PerformUniqueChecksTest(TestCase): | ||||
|             mtv = ModelToValidate(number=10, name='Some Name') | ||||
|             mtv.full_clean() | ||||
|  | ||||
|     def test_func_unique_check_not_performed(self): | ||||
|         with self.assertNumQueries(0): | ||||
|             UniqueFuncConstraintModel(field='some name').full_clean() | ||||
|  | ||||
|     def test_unique_for_date(self): | ||||
|         Post.objects.create( | ||||
|             title="Django 1.0 is released", slug="Django 1.0", | ||||
|   | ||||
		Reference in New Issue
	
	Block a user