diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py index eac61106c6..4f2fe5acb5 100644 --- a/django/db/models/sql/query.py +++ b/django/db/models/sql/query.py @@ -21,7 +21,9 @@ from django.core.exceptions import ( from django.db import DEFAULT_DB_ALIAS, NotSupportedError, connections from django.db.models.aggregates import Count from django.db.models.constants import LOOKUP_SEP -from django.db.models.expressions import BaseExpression, Col, F, Ref, SimpleCol +from django.db.models.expressions import ( + BaseExpression, Col, F, OuterRef, Ref, SimpleCol, +) from django.db.models.fields import Field from django.db.models.fields.related_lookups import MultiColSource from django.db.models.lookups import Lookup @@ -1639,6 +1641,9 @@ class Query(BaseExpression): saner null handling, and is easier for the backend's optimizer to handle. """ + filter_lhs, filter_rhs = filter_expr + if isinstance(filter_rhs, F): + filter_expr = (filter_lhs, OuterRef(filter_rhs.name)) # Generate the inner query. query = Query(self.model) query.add_filter(filter_expr) diff --git a/tests/queries/tests.py b/tests/queries/tests.py index 76f42fee73..373a0e224a 100644 --- a/tests/queries/tests.py +++ b/tests/queries/tests.py @@ -2776,6 +2776,12 @@ class ExcludeTests(TestCase): employment__title__in=('Engineer', 'Developer')).distinct().order_by('name') self.assertSequenceEqual(alex_nontech_employers, [google, intel, microsoft]) + def test_exclude_reverse_fk_field_ref(self): + tag = Tag.objects.create() + Note.objects.create(tag=tag, note='note') + annotation = Annotation.objects.create(name='annotation', tag=tag) + self.assertEqual(Annotation.objects.exclude(tag__note__note=F('name')).get(), annotation) + class ExcludeTest17600(TestCase): """