From f315d0423a09dfe20dd4d4f6a0eb11fc8e45a665 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Alexander=20Holmb=C3=A4ck?= <alexande.holmback@creuna.se>
Date: Thu, 6 Sep 2018 20:10:20 +0000
Subject: [PATCH] Fixed #29727 -- Made nonexistent joins in F() raise
 FieldError.

Regression in 2162f0983de0dfe2178531638ce7ea56f54dd4e7.
---
 django/db/models/sql/query.py | 5 ++++-
 docs/releases/2.1.2.txt       | 3 ++-
 tests/expressions/tests.py    | 4 ++++
 3 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
index 74eec72291..81f6f196d3 100644
--- a/django/db/models/sql/query.py
+++ b/django/db/models/sql/query.py
@@ -1594,10 +1594,13 @@ class Query:
         else:
             field_list = name.split(LOOKUP_SEP)
             join_info = self.setup_joins(field_list, self.get_meta(), self.get_initial_alias(), can_reuse=reuse)
-            targets, _, join_list = self.trim_joins(join_info.targets, join_info.joins, join_info.path)
+            targets, final_alias, join_list = self.trim_joins(join_info.targets, join_info.joins, join_info.path)
             if len(targets) > 1:
                 raise FieldError("Referencing multicolumn fields with F() objects "
                                  "isn't supported")
+            # Verify that the last lookup in name is a field or a transform:
+            # transform_function() raises FieldError if not.
+            join_info.transform_function(targets[0], final_alias)
             if reuse is not None:
                 reuse.update(join_list)
             col = _get_col(targets[0], join_info.targets[0], join_list[-1], simple_col)
diff --git a/docs/releases/2.1.2.txt b/docs/releases/2.1.2.txt
index 4ac5e25ef7..17c50fffd7 100644
--- a/docs/releases/2.1.2.txt
+++ b/docs/releases/2.1.2.txt
@@ -9,4 +9,5 @@ Django 2.1.2 fixes several bugs in 2.1.1
 Bugfixes
 ========
 
-* ...
+* Fixed a regression where nonexistent joins in ``F()`` no longer raised
+  ``FieldError`` (:ticket:`29727`).
diff --git a/tests/expressions/tests.py b/tests/expressions/tests.py
index 973176e223..9a646088b1 100644
--- a/tests/expressions/tests.py
+++ b/tests/expressions/tests.py
@@ -595,6 +595,10 @@ class BasicExpressionsTests(TestCase):
         with self.assertRaisesMessage(FieldError, "Cannot resolve keyword 'nope' into field."):
             list(Employee.objects.filter(firstname=F('nope')))
 
+    def test_incorrect_joined_field_in_F_expression(self):
+        with self.assertRaisesMessage(FieldError, "Cannot resolve keyword 'nope' into field."):
+            list(Company.objects.filter(ceo__pk=F('point_of_contact__nope')))
+
 
 class IterableLookupInnerExpressionsTests(TestCase):
     @classmethod