2
from operator import attrgetter
5
Country, Person, Group, Membership, Friendship, Article,
6
ArticleTranslation, ArticleTag, ArticleIdea, NewsArticle)
7
from django.test import TestCase
8
from django.utils.translation import activate
9
from django.core.exceptions import FieldError
10
from django import forms
12
# Note that these tests are testing internal implementation details.
13
# ForeignObject is not part of public API.
15
class MultiColumnFKTests(TestCase):
18
self.usa = Country.objects.create(name="United States of America")
19
self.soviet_union = Country.objects.create(name="Soviet Union")
24
self.bob.person_country = self.usa
26
self.jim = Person.objects.create(name='Jim', person_country=self.usa)
27
self.george = Person.objects.create(name='George', person_country=self.usa)
29
self.jane = Person.objects.create(name='Jane', person_country=self.soviet_union)
30
self.mark = Person.objects.create(name='Mark', person_country=self.soviet_union)
31
self.sam = Person.objects.create(name='Sam', person_country=self.soviet_union)
34
self.kgb = Group.objects.create(name='KGB', group_country=self.soviet_union)
35
self.cia = Group.objects.create(name='CIA', group_country=self.usa)
36
self.republican = Group.objects.create(name='Republican', group_country=self.usa)
37
self.democrat = Group.objects.create(name='Democrat', group_country=self.usa)
39
def test_get_succeeds_on_multicolumn_match(self):
40
# Membership objects have access to their related Person if both
41
# country_ids match between them
42
membership = Membership.objects.create(
43
membership_country_id=self.usa.id, person_id=self.bob.id, group_id=self.cia.id)
45
person = membership.person
46
self.assertEqual((person.id, person.name), (self.bob.id, "Bob"))
48
def test_get_fails_on_multicolumn_mismatch(self):
49
# Membership objects returns DoesNotExist error when the there is no
50
# Person with the same id and country_id
51
membership = Membership.objects.create(
52
membership_country_id=self.usa.id, person_id=self.jane.id, group_id=self.cia.id)
54
self.assertRaises(Person.DoesNotExist, getattr, membership, 'person')
56
def test_reverse_query_returns_correct_result(self):
57
# Creating a valid membership because it has the same country has the person
58
Membership.objects.create(
59
membership_country_id=self.usa.id, person_id=self.bob.id, group_id=self.cia.id)
61
# Creating an invalid membership because it has a different country has the person
62
Membership.objects.create(
63
membership_country_id=self.soviet_union.id, person_id=self.bob.id,
64
group_id=self.republican.id)
66
self.assertQuerysetEqual(
67
self.bob.membership_set.all(), [
70
attrgetter("group_id")
73
def test_query_filters_correctly(self):
75
# Creating a to valid memberships
76
Membership.objects.create(
77
membership_country_id=self.usa.id, person_id=self.bob.id, group_id=self.cia.id)
78
Membership.objects.create(
79
membership_country_id=self.usa.id, person_id=self.jim.id,
82
# Creating an invalid membership
83
Membership.objects.create(membership_country_id=self.soviet_union.id,
84
person_id=self.george.id, group_id=self.cia.id)
86
self.assertQuerysetEqual(
87
Membership.objects.filter(person__name__contains='o'), [
90
attrgetter("person_id")
93
def test_reverse_query_filters_correctly(self):
95
timemark = datetime.datetime.utcnow()
96
timedelta = datetime.timedelta(days=1)
98
# Creating a to valid memberships
99
Membership.objects.create(
100
membership_country_id=self.usa.id, person_id=self.bob.id,
101
group_id=self.cia.id, date_joined=timemark - timedelta)
102
Membership.objects.create(
103
membership_country_id=self.usa.id, person_id=self.jim.id,
104
group_id=self.cia.id, date_joined=timemark + timedelta)
106
# Creating an invalid membership
107
Membership.objects.create(
108
membership_country_id=self.soviet_union.id, person_id=self.george.id,
109
group_id=self.cia.id, date_joined=timemark + timedelta)
111
self.assertQuerysetEqual(
112
Person.objects.filter(membership__date_joined__gte=timemark), [
118
def test_forward_in_lookup_filters_correctly(self):
119
Membership.objects.create(membership_country_id=self.usa.id, person_id=self.bob.id,
120
group_id=self.cia.id)
121
Membership.objects.create(membership_country_id=self.usa.id, person_id=self.jim.id,
122
group_id=self.cia.id)
124
# Creating an invalid membership
125
Membership.objects.create(
126
membership_country_id=self.soviet_union.id, person_id=self.george.id,
127
group_id=self.cia.id)
129
self.assertQuerysetEqual(
130
Membership.objects.filter(person__in=[self.george, self.jim]), [
133
attrgetter('person_id')
136
self.assertQuerysetEqual(
137
Membership.objects.filter(person__in=Person.objects.filter(name='Jim')), [
140
attrgetter('person_id')
143
def test_select_related_foreignkey_forward_works(self):
144
Membership.objects.create(membership_country=self.usa, person=self.bob, group=self.cia)
145
Membership.objects.create(membership_country=self.usa, person=self.jim, group=self.democrat)
147
with self.assertNumQueries(1):
148
people = [m.person for m in Membership.objects.select_related('person').order_by('pk')]
150
normal_people = [m.person for m in Membership.objects.all().order_by('pk')]
151
self.assertEqual(people, normal_people)
153
def test_prefetch_foreignkey_forward_works(self):
154
Membership.objects.create(membership_country=self.usa, person=self.bob, group=self.cia)
155
Membership.objects.create(membership_country=self.usa, person=self.jim, group=self.democrat)
157
with self.assertNumQueries(2):
159
m.person for m in Membership.objects.prefetch_related('person').order_by('pk')]
161
normal_people = [m.person for m in Membership.objects.order_by('pk')]
162
self.assertEqual(people, normal_people)
164
def test_prefetch_foreignkey_reverse_works(self):
165
Membership.objects.create(membership_country=self.usa, person=self.bob, group=self.cia)
166
Membership.objects.create(membership_country=self.usa, person=self.jim, group=self.democrat)
167
with self.assertNumQueries(2):
169
list(p.membership_set.all())
170
for p in Person.objects.prefetch_related('membership_set').order_by('pk')]
172
normal_membership_sets = [list(p.membership_set.all())
173
for p in Person.objects.order_by('pk')]
174
self.assertEqual(membership_sets, normal_membership_sets)
176
def test_m2m_through_forward_returns_valid_members(self):
177
# We start out by making sure that the Group 'CIA' has no members.
178
self.assertQuerysetEqual(
179
self.cia.members.all(),
183
Membership.objects.create(membership_country=self.usa, person=self.bob, group=self.cia)
184
Membership.objects.create(membership_country=self.usa, person=self.jim, group=self.cia)
186
# Let's check to make sure that it worked. Bob and Jim should be members of the CIA.
188
self.assertQuerysetEqual(
189
self.cia.members.all(), [
192
], attrgetter("name")
195
def test_m2m_through_reverse_returns_valid_members(self):
196
# We start out by making sure that Bob is in no groups.
197
self.assertQuerysetEqual(
198
self.bob.groups.all(),
202
Membership.objects.create(membership_country=self.usa, person=self.bob, group=self.cia)
203
Membership.objects.create(membership_country=self.usa, person=self.bob,
204
group=self.republican)
206
# Bob should be in the CIA and a Republican
207
self.assertQuerysetEqual(
208
self.bob.groups.all(), [
211
], attrgetter("name")
214
def test_m2m_through_forward_ignores_invalid_members(self):
215
# We start out by making sure that the Group 'CIA' has no members.
216
self.assertQuerysetEqual(
217
self.cia.members.all(),
221
# Something adds jane to group CIA but Jane is in Soviet Union which isn't CIA's country
222
Membership.objects.create(membership_country=self.usa, person=self.jane, group=self.cia)
224
# There should still be no members in CIA
225
self.assertQuerysetEqual(
226
self.cia.members.all(),
230
def test_m2m_through_reverse_ignores_invalid_members(self):
231
# We start out by making sure that Jane has no groups.
232
self.assertQuerysetEqual(
233
self.jane.groups.all(),
237
# Something adds jane to group CIA but Jane is in Soviet Union which isn't CIA's country
238
Membership.objects.create(membership_country=self.usa, person=self.jane, group=self.cia)
240
# Jane should still not be in any groups
241
self.assertQuerysetEqual(
242
self.jane.groups.all(),
246
def test_m2m_through_on_self_works(self):
247
self.assertQuerysetEqual(
248
self.jane.friends.all(),
252
Friendship.objects.create(
253
from_friend_country=self.jane.person_country, from_friend=self.jane,
254
to_friend_country=self.george.person_country, to_friend=self.george)
256
self.assertQuerysetEqual(
257
self.jane.friends.all(),
258
['George'], attrgetter("name")
261
def test_m2m_through_on_self_ignores_mismatch_columns(self):
262
self.assertQuerysetEqual(self.jane.friends.all(), [])
264
# Note that we use ids instead of instances. This is because instances on ForeignObject
265
# properties will set all related field off of the given instance
266
Friendship.objects.create(
267
from_friend_id=self.jane.id, to_friend_id=self.george.id,
268
to_friend_country_id=self.jane.person_country_id,
269
from_friend_country_id=self.george.person_country_id)
271
self.assertQuerysetEqual(self.jane.friends.all(), [])
273
def test_prefetch_related_m2m_foward_works(self):
274
Membership.objects.create(membership_country=self.usa, person=self.bob, group=self.cia)
275
Membership.objects.create(membership_country=self.usa, person=self.jim, group=self.democrat)
277
with self.assertNumQueries(2):
278
members_lists = [list(g.members.all())
279
for g in Group.objects.prefetch_related('members')]
281
normal_members_lists = [list(g.members.all()) for g in Group.objects.all()]
282
self.assertEqual(members_lists, normal_members_lists)
284
def test_prefetch_related_m2m_reverse_works(self):
285
Membership.objects.create(membership_country=self.usa, person=self.bob, group=self.cia)
286
Membership.objects.create(membership_country=self.usa, person=self.jim, group=self.democrat)
288
with self.assertNumQueries(2):
289
groups_lists = [list(p.groups.all()) for p in Person.objects.prefetch_related('groups')]
291
normal_groups_lists = [list(p.groups.all()) for p in Person.objects.all()]
292
self.assertEqual(groups_lists, normal_groups_lists)
294
def test_translations(self):
296
a1 = Article.objects.create(pub_date=datetime.date.today())
297
at1_fi = ArticleTranslation(article=a1, lang='fi', title='Otsikko', body='Diipadaapa')
299
at2_en = ArticleTranslation(article=a1, lang='en', title='Title', body='Lalalalala')
301
with self.assertNumQueries(1):
302
fetched = Article.objects.select_related('active_translation').get(
303
active_translation__title='Otsikko')
304
self.assertTrue(fetched.active_translation.title == 'Otsikko')
305
a2 = Article.objects.create(pub_date=datetime.date.today())
306
at2_fi = ArticleTranslation(article=a2, lang='fi', title='Atsikko', body='Diipadaapa',
309
a3 = Article.objects.create(pub_date=datetime.date.today())
310
at3_en = ArticleTranslation(article=a3, lang='en', title='A title', body='lalalalala',
313
# Test model initialization with active_translation field.
314
a3 = Article(id=a3.id, pub_date=a3.pub_date, active_translation=at3_en)
317
list(Article.objects.filter(active_translation__abstract=None)),
320
list(Article.objects.filter(active_translation__abstract=None,
321
active_translation__pk__isnull=False)),
325
list(Article.objects.filter(active_translation__abstract=None)),
328
def test_foreign_key_raises_informative_does_not_exist(self):
329
referrer = ArticleTranslation()
330
with self.assertRaisesMessage(Article.DoesNotExist, 'ArticleTranslation has no article'):
333
def test_foreign_key_related_query_name(self):
334
a1 = Article.objects.create(pub_date=datetime.date.today())
335
ArticleTag.objects.create(article=a1, name="foo")
336
self.assertEqual(Article.objects.filter(tag__name="foo").count(), 1)
337
self.assertEqual(Article.objects.filter(tag__name="bar").count(), 0)
338
with self.assertRaises(FieldError):
339
Article.objects.filter(tags__name="foo")
341
def test_many_to_many_related_query_name(self):
342
a1 = Article.objects.create(pub_date=datetime.date.today())
343
i1 = ArticleIdea.objects.create(name="idea1")
345
self.assertEqual(Article.objects.filter(idea_things__name="idea1").count(), 1)
346
self.assertEqual(Article.objects.filter(idea_things__name="idea2").count(), 0)
347
with self.assertRaises(FieldError):
348
Article.objects.filter(ideas__name="idea1")
350
def test_inheritance(self):
352
na = NewsArticle.objects.create(pub_date=datetime.date.today())
353
ArticleTranslation.objects.create(
354
article=na, lang="fi", title="foo", body="bar")
355
self.assertQuerysetEqual(
356
NewsArticle.objects.select_related('active_translation'),
359
with self.assertNumQueries(1):
361
NewsArticle.objects.select_related(
362
'active_translation')[0].active_translation.title,
365
class FormsTests(TestCase):
366
# ForeignObjects should not have any form fields, currently the user needs
367
# to manually deal with the foreignobject relation.
368
class ArticleForm(forms.ModelForm):
373
def test_foreign_object_form(self):
374
# A very crude test checking that the non-concrete fields do not get form fields.
375
form = FormsTests.ArticleForm()
376
self.assertIn('id_pub_date', form.as_table())
377
self.assertNotIn('active_translation', form.as_table())
378
form = FormsTests.ArticleForm(data={'pub_date': str(datetime.date.today())})
379
self.assertTrue(form.is_valid())
381
self.assertEqual(a.pub_date, datetime.date.today())
382
form = FormsTests.ArticleForm(instance=a, data={'pub_date': '2013-01-01'})
384
self.assertEqual(a.pk, a2.pk)
385
self.assertEqual(a2.pub_date, datetime.date(2013, 1, 1))