1
from __future__ import absolute_import, unicode_literals
3
from django.test import TestCase
4
from django.utils import six
6
from .models import (Building, Child, Device, Port, Item, Country, Connection,
7
ClientStatus, State, Client, SpecialClient, TUser, Person, Student,
8
Organizer, Class, Enrollment, Hen, Chick)
11
class SelectRelatedRegressTests(TestCase):
13
def test_regression_7110(self):
15
Regression test for bug #7110.
17
When using select_related(), we must query the
18
Device and Building tables using two different aliases (each) in order to
19
differentiate the start and end Connection fields. The net result is that
20
both the "connections = ..." queries here should give the same results
21
without pulling in more than the absolute minimum number of tables
22
(history has shown that it's easy to make a mistake in the implementation
23
and include some unnecessary bonus joins).
26
b=Building.objects.create(name='101')
27
dev1=Device.objects.create(name="router", building=b)
28
dev2=Device.objects.create(name="switch", building=b)
29
dev3=Device.objects.create(name="server", building=b)
30
port1=Port.objects.create(port_number='4',device=dev1)
31
port2=Port.objects.create(port_number='7',device=dev2)
32
port3=Port.objects.create(port_number='1',device=dev3)
33
c1=Connection.objects.create(start=port1, end=port2)
34
c2=Connection.objects.create(start=port2, end=port3)
36
connections=Connection.objects.filter(start__device__building=b, end__device__building=b).order_by('id')
37
self.assertEqual([(c.id, six.text_type(c.start), six.text_type(c.end)) for c in connections],
38
[(c1.id, 'router/4', 'switch/7'), (c2.id, 'switch/7', 'server/1')])
40
connections=Connection.objects.filter(start__device__building=b, end__device__building=b).select_related().order_by('id')
41
self.assertEqual([(c.id, six.text_type(c.start), six.text_type(c.end)) for c in connections],
42
[(c1.id, 'router/4', 'switch/7'), (c2.id, 'switch/7', 'server/1')])
44
# This final query should only have seven tables (port, device and building
45
# twice each, plus connection once). Thus, 6 joins plus the FROM table.
46
self.assertEqual(str(connections.query).count(" JOIN "), 6)
49
def test_regression_8106(self):
51
Regression test for bug #8106.
53
Same sort of problem as the previous test, but this time there are
54
more extra tables to pull in as part of the select_related() and some
55
of them could potentially clash (so need to be kept separate).
58
us = TUser.objects.create(name="std")
59
usp = Person.objects.create(user=us)
60
uo = TUser.objects.create(name="org")
61
uop = Person.objects.create(user=uo)
62
s = Student.objects.create(person = usp)
63
o = Organizer.objects.create(person = uop)
64
c = Class.objects.create(org=o)
65
e = Enrollment.objects.create(std=s, cls=c)
67
e_related = Enrollment.objects.all().select_related()[0]
68
self.assertEqual(e_related.std.person.user.name, "std")
69
self.assertEqual(e_related.cls.org.person.user.name, "org")
71
def test_regression_8036(self):
73
Regression test for bug #8036
75
the first related model in the tests below
76
("state") is empty and we try to select the more remotely related
77
state__country. The regression here was not skipping the empty column results
78
for country before getting status.
81
australia = Country.objects.create(name='Australia')
82
active = ClientStatus.objects.create(name='active')
83
client = Client.objects.create(name='client', status=active)
85
self.assertEqual(client.status, active)
86
self.assertEqual(Client.objects.select_related()[0].status, active)
87
self.assertEqual(Client.objects.select_related('state')[0].status, active)
88
self.assertEqual(Client.objects.select_related('state', 'status')[0].status, active)
89
self.assertEqual(Client.objects.select_related('state__country')[0].status, active)
90
self.assertEqual(Client.objects.select_related('state__country', 'status')[0].status, active)
91
self.assertEqual(Client.objects.select_related('status')[0].status, active)
93
def test_multi_table_inheritance(self):
94
""" Exercising select_related() with multi-table model inheritance. """
95
c1 = Child.objects.create(name="child1", value=42)
96
i1 = Item.objects.create(name="item1", child=c1)
97
i2 = Item.objects.create(name="item2")
99
self.assertQuerysetEqual(
100
Item.objects.select_related("child").order_by("name"),
101
["<Item: item1>", "<Item: item2>"]
104
def test_regression_12851(self):
106
Regression for #12851
108
Deferred fields are used correctly if you select_related a subset
111
australia = Country.objects.create(name='Australia')
112
active = ClientStatus.objects.create(name='active')
114
wa = State.objects.create(name="Western Australia", country=australia)
115
c1 = Client.objects.create(name='Brian Burke', state=wa, status=active)
116
burke = Client.objects.select_related('state').defer('state__name').get(name='Brian Burke')
118
self.assertEqual(burke.name, 'Brian Burke')
119
self.assertEqual(burke.state.name, 'Western Australia')
121
# Still works if we're dealing with an inherited class
122
sc1 = SpecialClient.objects.create(name='Troy Buswell', state=wa, status=active, value=42)
123
troy = SpecialClient.objects.select_related('state').defer('state__name').get(name='Troy Buswell')
125
self.assertEqual(troy.name, 'Troy Buswell')
126
self.assertEqual(troy.value, 42)
127
self.assertEqual(troy.state.name, 'Western Australia')
129
# Still works if we defer an attribute on the inherited class
130
troy = SpecialClient.objects.select_related('state').defer('value', 'state__name').get(name='Troy Buswell')
132
self.assertEqual(troy.name, 'Troy Buswell')
133
self.assertEqual(troy.value, 42)
134
self.assertEqual(troy.state.name, 'Western Australia')
136
# Also works if you use only, rather than defer
137
troy = SpecialClient.objects.select_related('state').only('name', 'state').get(name='Troy Buswell')
139
self.assertEqual(troy.name, 'Troy Buswell')
140
self.assertEqual(troy.value, 42)
141
self.assertEqual(troy.state.name, 'Western Australia')
143
def test_null_join_promotion(self):
144
australia = Country.objects.create(name='Australia')
145
active = ClientStatus.objects.create(name='active')
147
wa = State.objects.create(name="Western Australia", country=australia)
148
bob = Client.objects.create(name='Bob', status=active)
149
jack = Client.objects.create(name='Jack', status=active, state=wa)
150
qs = Client.objects.filter(state=wa).select_related('state')
151
with self.assertNumQueries(1):
152
self.assertEqual(list(qs), [jack])
153
self.assertEqual(qs[0].state, wa)
154
# The select_related join wasn't promoted as there was already an
155
# existing (even if trimmed) inner join to state.
156
self.assertFalse('LEFT OUTER' in str(qs.query))
157
qs = Client.objects.select_related('state').order_by('name')
158
with self.assertNumQueries(1):
159
self.assertEqual(list(qs), [bob, jack])
160
self.assertIs(qs[0].state, None)
161
self.assertEqual(qs[1].state, wa)
162
# The select_related join was promoted as there is already an
164
self.assertTrue('LEFT OUTER' in str(qs.query))
166
def test_regression_19870(self):
168
Regression for #19870
171
hen = Hen.objects.create(name='Hen')
172
chick = Chick.objects.create(name='Chick', mother=hen)
174
self.assertEqual(Chick.objects.all()[0].mother.name, 'Hen')
175
self.assertEqual(Chick.objects.select_related()[0].mother.name, 'Hen')