﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
36580	Model validation of constraints fails if condition's Q object references ForeignObject	Jacob Walls	JaeHyuckSa	"Similar to #36433, just for `ForeignObject` instead of `ForeignKey`.

With this adjusted test model and corresponding adjustment to unrelated test, `test_full_clean_update` passes on stable/5.2.x (the constraint is purposefully not very imaginative, can polish in PR review):
{{{#!diff
diff --git a/tests/composite_pk/models/tenant.py b/tests/composite_pk/models/tenant.py
index 65eb0feae8..954a5519f8 100644
--- a/tests/composite_pk/models/tenant.py
+++ b/tests/composite_pk/models/tenant.py
@@ -48,6 +48,14 @@ class Comment(models.Model):
     text = models.TextField(default="""", blank=True)
     integer = models.IntegerField(default=0)
 
+    class Meta:
+        constraints = [
+            models.CheckConstraint(
+                condition=models.Q(user__isnull=False),
+                name=""user_not_null"",
+            ),
+        ]
+
 
 class Post(models.Model):
     pk = models.CompositePrimaryKey(""tenant_id"", ""id"")
diff --git a/tests/composite_pk/tests.py b/tests/composite_pk/tests.py
index c4a8e6ca8c..cade405dee 100644
--- a/tests/composite_pk/tests.py
+++ b/tests/composite_pk/tests.py
@@ -205,12 +205,17 @@ class CompositePKTests(TestCase):
             self.assertEqual(user.email, self.user.email)
 
     def test_select_related(self):
-        Comment.objects.create(tenant=self.tenant, id=2)
+        user2 = User.objects.create(
+            tenant=self.tenant,
+            id=2,
+            email=""user0002@example.com"",
+        )
+        Comment.objects.create(tenant=self.tenant, id=2, user=user2)
         with self.assertNumQueries(1):
             comments = list(Comment.objects.select_related(""user"").order_by(""pk""))
             self.assertEqual(len(comments), 2)
             self.assertEqual(comments[0].user, self.user)
-            self.assertIsNone(comments[1].user)
+            self.assertEqual(comments[1].user, user2)
 
     def test_model_forms(self):
         fields = [""tenant"", ""id"", ""user_id"", ""text"", ""integer""]
}}}

... but fails on main:
{{{#!py
======================================================================
ERROR: test_full_clean_update (composite_pk.test_models.CompositePKModelsTests.test_full_clean_update)
----------------------------------------------------------------------
Traceback (most recent call last):
  File ""/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/unittest/case.py"", line 58, in testPartExecutor
    yield
  File ""/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/unittest/case.py"", line 651, in run
    self._callTestMethod(testMethod)
    
  File ""/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/unittest/case.py"", line 606, in _callTestMethod
    if method() is not None:
    ^^^^^^^^^^^^^^^
  File ""/Users/jwalls/django/tests/composite_pk/test_models.py"", line 123, in test_full_clean_update
    self.comment_1.full_clean()
    ^^^^^^^^^^^
  File ""/Users/jwalls/django/django/db/models/base.py"", line 1638, in full_clean
    self.validate_constraints(exclude=exclude)
    ^^^^^^^
  File ""/Users/jwalls/django/django/db/models/base.py"", line 1586, in validate_constraints
    constraint.validate(model_class, self, exclude=exclude, using=using)
    ^^^
  File ""/Users/jwalls/django/django/db/models/constraints.py"", line 212, in validate
    if not Q(self.condition).check(against, using=using):
    ^^^^^^^^^^^^^^^
  File ""/Users/jwalls/django/django/db/models/query_utils.py"", line 176, in check
    query.add_q(Q(Coalesce(self, True, output_field=BooleanField())))
    ^^^^^^^^^^^
  File ""/Users/jwalls/django/django/db/models/sql/query.py"", line 1670, in add_q
    clause, _ = self._add_q(q_object, can_reuse)
    ^^^^^^^^^^^^^^^
  File ""/Users/jwalls/django/django/db/models/sql/query.py"", line 1702, in _add_q
    child_clause, needed_inner = self.build_filter(
    ^^^^^^^^^^^
  File ""/Users/jwalls/django/django/db/models/sql/query.py"", line 1541, in build_filter
    condition = filter_expr.resolve_expression(
    ^^^^^^^^^^^
  File ""/Users/jwalls/django/django/db/models/expressions.py"", line 301, in resolve_expression
    expr.resolve_expression(query, allow_joins, reuse, summarize, for_save)
    ^^^^^^^
  File ""/Users/jwalls/django/django/db/models/query_utils.py"", line 91, in resolve_expression
    clause, joins = query._add_q(
    ^^^^^^^^^^^^^^^
  File ""/Users/jwalls/django/django/db/models/sql/query.py"", line 1702, in _add_q
    child_clause, needed_inner = self.build_filter(
    ^^^^^^^^^^^
  File ""/Users/jwalls/django/django/db/models/sql/query.py"", line 1527, in build_filter
    return self._add_q(
    ^^^^^^^^^^^
  File ""/Users/jwalls/django/django/db/models/sql/query.py"", line 1702, in _add_q
    child_clause, needed_inner = self.build_filter(
    ^^^^^^^^^^^
  File ""/Users/jwalls/django/django/db/models/sql/query.py"", line 1550, in build_filter
    lookups, parts, reffed_expression = self.solve_lookup_type(arg, summarize)
    ^^^^^^^^^^^^^^^
  File ""/Users/jwalls/django/django/db/models/sql/query.py"", line 1357, in solve_lookup_type
    _, field, _, lookup_parts = self.names_to_path(lookup_splitted, self.get_meta())
    ^^^^^^^^^^^^^^^
  File ""/Users/jwalls/django/django/db/models/sql/query.py"", line 1830, in names_to_path
    raise FieldError(
    ^^^
django.core.exceptions.FieldError: Cannot resolve keyword 'user' into field. Choices are: _check

----------------------------------------------------------------------
Ran 178 tests in 1.224s
}}}

---

There is a prior comment in ticket:36433#comment:1 about improving the error message."	Bug	closed	Database layer (models, ORM)	dev	Release blocker	fixed			Ready for checkin	1	0	0	0	0	0
