diff --git a/django/contrib/postgres/constraints.py b/django/contrib/postgres/constraints.py index a6351dc008..2701c4ba48 100644 --- a/django/contrib/postgres/constraints.py +++ b/django/contrib/postgres/constraints.py @@ -178,7 +178,7 @@ class ExclusionConstraint(BaseConstraint): def validate(self, model, instance, exclude=None, using=DEFAULT_DB_ALIAS): queryset = model._default_manager.using(using) - replacement_map = instance._get_field_value_map( + replacement_map = instance._get_field_expression_map( meta=model._meta, exclude=exclude ) replacements = {F(field): value for field, value in replacement_map.items()} diff --git a/django/db/models/base.py b/django/db/models/base.py index 9f8c1c0cc0..d4b8bab963 100644 --- a/django/db/models/base.py +++ b/django/db/models/base.py @@ -1333,12 +1333,17 @@ class Model(AltersData, metaclass=ModelBase): setattr(self, cachename, obj) return getattr(self, cachename) - def _get_field_value_map(self, meta, exclude=None): + def _get_field_expression_map(self, meta, exclude=None): if exclude is None: exclude = set() meta = meta or self._meta field_map = { - field.name: Value(getattr(self, field.attname), field) + field.name: ( + value + if (value := getattr(self, field.attname)) + and hasattr(value, "resolve_expression") + else Value(value, field) + ) for field in meta.local_concrete_fields if field.name not in exclude and not field.generated } diff --git a/django/db/models/constraints.py b/django/db/models/constraints.py index 0a63e38d83..915ace5129 100644 --- a/django/db/models/constraints.py +++ b/django/db/models/constraints.py @@ -241,7 +241,7 @@ class CheckConstraint(BaseConstraint): return schema_editor._delete_check_sql(model, self.name) def validate(self, model, instance, exclude=None, using=DEFAULT_DB_ALIAS): - against = instance._get_field_value_map(meta=model._meta, exclude=exclude) + against = instance._get_field_expression_map(meta=model._meta, exclude=exclude) try: if not Q(self.condition).check(against, using=using): raise ValidationError( @@ -638,7 +638,7 @@ class UniqueConstraint(BaseConstraint): return replacements = { F(field): value - for field, value in instance._get_field_value_map( + for field, value in instance._get_field_expression_map( meta=model._meta, exclude=exclude ).items() } @@ -668,7 +668,9 @@ class UniqueConstraint(BaseConstraint): code=self.violation_error_code, ) else: - against = instance._get_field_value_map(meta=model._meta, exclude=exclude) + against = instance._get_field_expression_map( + meta=model._meta, exclude=exclude + ) try: if (self.condition & Exists(queryset.filter(self.condition))).check( against, using=using