Code

Ticket #14694: 14694-defer-reverse-relations-r17008.2.diff

File 14694-defer-reverse-relations-r17008.2.diff, 4.0 KB (added by mrmachine, 3 years ago)
Line 
1Index: tests/regressiontests/defer_regress/tests.py
2===================================================================
3--- tests/regressiontests/defer_regress/tests.py        (revision 17014)
4+++ tests/regressiontests/defer_regress/tests.py        (working copy)
5@@ -9,7 +9,7 @@
6 from django.test import TestCase
7 
8 from .models import (ResolveThis, Item, RelatedItem, Child, Leaf, Proxy,
9-    SimpleItem, Feature)
10+    SimpleItem, Feature, OneToOneItem)
11 
12 
13 class DeferRegressionTest(TestCase):
14@@ -110,6 +110,7 @@
15                 Feature,
16                 Item,
17                 Leaf,
18+                OneToOneItem,
19                 Proxy,
20                 RelatedItem,
21                 ResolveThis,
22@@ -141,6 +142,7 @@
23                 "Leaf_Deferred_name_value",
24                 "Leaf_Deferred_second_child_value",
25                 "Leaf_Deferred_value",
26+                "OneToOneItem",
27                 "Proxy",
28                 "RelatedItem",
29                 "RelatedItem_Deferred_",
30@@ -174,3 +176,9 @@
31         qs = ResolveThis.objects.defer('num')
32         self.assertEqual(1, qs.count())
33         self.assertEqual('Foobar', qs[0].name)
34+
35+    def test_reverse_one_to_one_relations(self):
36+        item = Item.objects.create(name="first", value=42)
37+        OneToOneItem.objects.create(item=item, name="second")
38+        self.assertEqual(len(Item.objects.all()), 1)
39+        self.assertEqual(len(Item.objects.defer('one_to_one_item__name')), 1)
40Index: tests/regressiontests/defer_regress/models.py
41===================================================================
42--- tests/regressiontests/defer_regress/models.py       (revision 17014)
43+++ tests/regressiontests/defer_regress/models.py       (working copy)
44@@ -47,3 +47,7 @@
45 
46 class Feature(models.Model):
47     item = models.ForeignKey(SimpleItem)
48+
49+class OneToOneItem(models.Model):
50+    item = models.OneToOneField(Item, related_name="one_to_one_item")
51+    name = models.CharField(max_length=15)
52Index: django/db/models/sql/query.py
53===================================================================
54--- django/db/models/sql/query.py       (revision 17014)
55+++ django/db/models/sql/query.py       (working copy)
56@@ -16,6 +16,7 @@
57 from django.db.models import signals
58 from django.db.models.fields import FieldDoesNotExist
59 from django.db.models.query_utils import InvalidQuery
60+from django.db.models.related import RelatedObject
61 from django.db.models.sql import aggregates as base_aggregates_module
62 from django.db.models.sql.constants import *
63 from django.db.models.sql.datastructures import EmptyResultSet, Empty, MultiJoin
64@@ -580,12 +581,17 @@
65             for name in parts[:-1]:
66                 old_model = cur_model
67                 source = opts.get_field_by_name(name)[0]
68-                cur_model = opts.get_field_by_name(name)[0].rel.to
69+                if isinstance(source, RelatedObject):
70+                    cur_model = source.model
71+                else:
72+                    cur_model = source.rel.to
73                 opts = cur_model._meta
74                 # Even if we're "just passing through" this model, we must add
75                 # both the current model's pk and the related reference field
76                 # to the things we select.
77-                must_include[old_model].add(source)
78+                # (if it's not a reverse relation) to the things we select.
79+                if not isinstance(source, RelatedObject):
80+                    must_include[old_model].add(source)
81                 add_to_dict(must_include, cur_model, opts.pk)
82             field, model, _, _ = opts.get_field_by_name(parts[-1])
83             if model is None:
84@@ -630,7 +636,6 @@
85             for model, values in seen.iteritems():
86                 callback(target, model, values)
87 
88-
89     def deferred_to_columns_cb(self, target, model, fields):
90         """
91         Callback used by deferred_to_columns(). The "target" parameter should
92@@ -642,7 +647,6 @@
93         for field in fields:
94             target[table].add(field.column)
95 
96-
97     def table_alias(self, table_name, create=False):
98         """
99         Returns a table alias for the given table_name and whether this is a