summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Johnson <me@adamj.eu>2025-11-12 19:47:16 +0000
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2025-11-13 10:04:40 +0100
commit5ae8659cb5beb9e4bea36a1c1b2e443bff4f3873 (patch)
treeea7e2aa767b15ad01d55286ed79c0a74d239a086
parentd6af15d44dbc208b3c80c9b019b9091a3c527385 (diff)
[6.0.x] Fixed #36730 -- Fixed constraint validation crash for excluded FK attnames.
Regression in e44e8327d3d88d86895735c0e427102063ff5b55. Co-authored-by: Mariusz Felisiak <felisiak.mariusz@gmail.com> Backport of abfa4619fb818ff694c22e962a280673e085239e from main
-rw-r--r--django/db/models/constraints.py7
-rw-r--r--tests/model_forms/models.py19
-rw-r--r--tests/model_forms/tests.py15
3 files changed, 39 insertions, 2 deletions
diff --git a/django/db/models/constraints.py b/django/db/models/constraints.py
index 73ab23bdfa..93251ff322 100644
--- a/django/db/models/constraints.py
+++ b/django/db/models/constraints.py
@@ -51,9 +51,12 @@ class BaseConstraint:
def _expression_refs_exclude(cls, model, expression, exclude):
get_field = model._meta.get_field
for field_name, *__ in model._get_expr_references(expression):
- if field_name in exclude:
+ if field_name == "pk":
+ field = model._meta.pk
+ else:
+ field = get_field(field_name)
+ if field_name in exclude or field.name in exclude:
return True
- field = get_field(field_name)
if field.generated and cls._expression_refs_exclude(
model, field.expression, exclude
):
diff --git a/tests/model_forms/models.py b/tests/model_forms/models.py
index f6c34a3521..83daa13d71 100644
--- a/tests/model_forms/models.py
+++ b/tests/model_forms/models.py
@@ -543,3 +543,22 @@ class ConstraintsModel(models.Model):
violation_error_message="Price must be greater than zero.",
),
]
+
+
+class AttnameConstraintsModel(models.Model):
+ left = models.ForeignKey(
+ "self", related_name="+", null=True, on_delete=models.SET_NULL
+ )
+ right = models.ForeignKey(
+ "self", related_name="+", null=True, on_delete=models.SET_NULL
+ )
+
+ class Meta:
+ required_db_features = {"supports_table_check_constraints"}
+ constraints = [
+ models.CheckConstraint(
+ name="%(app_label)s_%(class)s_left_not_right",
+ # right_id here is the ForeignKey's attname, not name.
+ condition=~models.Q(left=models.F("right_id")),
+ ),
+ ]
diff --git a/tests/model_forms/tests.py b/tests/model_forms/tests.py
index f0334e1e86..129ce56c7a 100644
--- a/tests/model_forms/tests.py
+++ b/tests/model_forms/tests.py
@@ -30,6 +30,7 @@ from django.utils.version import PY314, PYPY
from .models import (
Article,
ArticleStatus,
+ AttnameConstraintsModel,
Author,
Author1,
Award,
@@ -3766,3 +3767,17 @@ class ConstraintValidationTests(TestCase):
self.assertEqual(
full_form.errors, {"__all__": ["Price must be greater than zero."]}
)
+
+ def test_check_constraint_refs_excluded_field_attname(self):
+ left = AttnameConstraintsModel.objects.create()
+ instance = AttnameConstraintsModel.objects.create(left=left)
+ data = {
+ "left": str(left.id),
+ "right": "",
+ }
+ AttnameConstraintsModelForm = modelform_factory(
+ AttnameConstraintsModel, fields="__all__"
+ )
+ full_form = AttnameConstraintsModelForm(data, instance=instance)
+ self.assertFalse(full_form.is_valid())
+ self.assertEqual(full_form.errors, {"right": ["This field is required."]})