|
1 import datetime |
|
2 import pickle |
|
3 import sys |
|
4 import unittest |
|
5 |
|
6 from django.conf import settings |
|
7 from django.core.exceptions import FieldError |
|
8 from django.db import DatabaseError, connection, connections, DEFAULT_DB_ALIAS |
|
9 from django.db.models import Count |
|
10 from django.db.models.query import Q, ITER_CHUNK_SIZE, EmptyQuerySet |
|
11 from django.test import TestCase |
|
12 from django.utils.datastructures import SortedDict |
|
13 |
|
14 from models import (Annotation, Article, Author, Celebrity, Child, Cover, Detail, |
|
15 DumbCategory, ExtraInfo, Fan, Item, LeafA, LoopX, LoopZ, ManagedModel, |
|
16 Member, NamedCategory, Note, Number, Plaything, PointerA, Ranking, Related, |
|
17 Report, ReservedName, Tag, TvChef, Valid, X) |
|
18 |
|
19 |
|
20 class BaseQuerysetTest(TestCase): |
|
21 def assertValueQuerysetEqual(self, qs, values): |
|
22 return self.assertQuerysetEqual(qs, values, transform=lambda x: x) |
|
23 |
|
24 def assertRaisesMessage(self, exc, msg, func, *args, **kwargs): |
|
25 try: |
|
26 func(*args, **kwargs) |
|
27 except Exception, e: |
|
28 self.assertEqual(msg, str(e)) |
|
29 self.assertTrue(isinstance(e, exc), "Expected %s, got %s" % (exc, type(e))) |
|
30 else: |
|
31 if hasattr(exc, '__name__'): |
|
32 excName = exc.__name__ |
|
33 else: |
|
34 excName = str(exc) |
|
35 raise AssertionError, "%s not raised" % excName |
|
36 |
|
37 |
|
38 class Queries1Tests(BaseQuerysetTest): |
|
39 def setUp(self): |
|
40 generic = NamedCategory.objects.create(name="Generic") |
|
41 self.t1 = Tag.objects.create(name='t1', category=generic) |
|
42 self.t2 = Tag.objects.create(name='t2', parent=self.t1, category=generic) |
|
43 self.t3 = Tag.objects.create(name='t3', parent=self.t1) |
|
44 t4 = Tag.objects.create(name='t4', parent=self.t3) |
|
45 self.t5 = Tag.objects.create(name='t5', parent=self.t3) |
|
46 |
|
47 self.n1 = Note.objects.create(note='n1', misc='foo', id=1) |
|
48 n2 = Note.objects.create(note='n2', misc='bar', id=2) |
|
49 self.n3 = Note.objects.create(note='n3', misc='foo', id=3) |
|
50 |
|
51 ann1 = Annotation.objects.create(name='a1', tag=self.t1) |
|
52 ann1.notes.add(self.n1) |
|
53 ann2 = Annotation.objects.create(name='a2', tag=t4) |
|
54 ann2.notes.add(n2, self.n3) |
|
55 |
|
56 # Create these out of order so that sorting by 'id' will be different to sorting |
|
57 # by 'info'. Helps detect some problems later. |
|
58 self.e2 = ExtraInfo.objects.create(info='e2', note=n2) |
|
59 e1 = ExtraInfo.objects.create(info='e1', note=self.n1) |
|
60 |
|
61 self.a1 = Author.objects.create(name='a1', num=1001, extra=e1) |
|
62 self.a2 = Author.objects.create(name='a2', num=2002, extra=e1) |
|
63 a3 = Author.objects.create(name='a3', num=3003, extra=self.e2) |
|
64 self.a4 = Author.objects.create(name='a4', num=4004, extra=self.e2) |
|
65 |
|
66 self.time1 = datetime.datetime(2007, 12, 19, 22, 25, 0) |
|
67 self.time2 = datetime.datetime(2007, 12, 19, 21, 0, 0) |
|
68 time3 = datetime.datetime(2007, 12, 20, 22, 25, 0) |
|
69 time4 = datetime.datetime(2007, 12, 20, 21, 0, 0) |
|
70 self.i1 = Item.objects.create(name='one', created=self.time1, modified=self.time1, creator=self.a1, note=self.n3) |
|
71 self.i1.tags = [self.t1, self.t2] |
|
72 self.i2 = Item.objects.create(name='two', created=self.time2, creator=self.a2, note=n2) |
|
73 self.i2.tags = [self.t1, self.t3] |
|
74 self.i3 = Item.objects.create(name='three', created=time3, creator=self.a2, note=self.n3) |
|
75 i4 = Item.objects.create(name='four', created=time4, creator=self.a4, note=self.n3) |
|
76 i4.tags = [t4] |
|
77 |
|
78 self.r1 = Report.objects.create(name='r1', creator=self.a1) |
|
79 Report.objects.create(name='r2', creator=a3) |
|
80 Report.objects.create(name='r3') |
|
81 |
|
82 # Ordering by 'rank' gives us rank2, rank1, rank3. Ordering by the Meta.ordering |
|
83 # will be rank3, rank2, rank1. |
|
84 self.rank1 = Ranking.objects.create(rank=2, author=self.a2) |
|
85 |
|
86 Cover.objects.create(title="first", item=i4) |
|
87 Cover.objects.create(title="second", item=self.i2) |
|
88 |
|
89 def test_ticket1050(self): |
|
90 self.assertQuerysetEqual( |
|
91 Item.objects.filter(tags__isnull=True), |
|
92 ['<Item: three>'] |
|
93 ) |
|
94 self.assertQuerysetEqual( |
|
95 Item.objects.filter(tags__id__isnull=True), |
|
96 ['<Item: three>'] |
|
97 ) |
|
98 |
|
99 def test_ticket1801(self): |
|
100 self.assertQuerysetEqual( |
|
101 Author.objects.filter(item=self.i2), |
|
102 ['<Author: a2>'] |
|
103 ) |
|
104 self.assertQuerysetEqual( |
|
105 Author.objects.filter(item=self.i3), |
|
106 ['<Author: a2>'] |
|
107 ) |
|
108 self.assertQuerysetEqual( |
|
109 Author.objects.filter(item=self.i2) & Author.objects.filter(item=self.i3), |
|
110 ['<Author: a2>'] |
|
111 ) |
|
112 |
|
113 def test_ticket2306(self): |
|
114 # Checking that no join types are "left outer" joins. |
|
115 query = Item.objects.filter(tags=self.t2).query |
|
116 self.assertTrue(query.LOUTER not in [x[2] for x in query.alias_map.values()]) |
|
117 |
|
118 self.assertQuerysetEqual( |
|
119 Item.objects.filter(Q(tags=self.t1)).order_by('name'), |
|
120 ['<Item: one>', '<Item: two>'] |
|
121 ) |
|
122 self.assertQuerysetEqual( |
|
123 Item.objects.filter(Q(tags=self.t1)).filter(Q(tags=self.t2)), |
|
124 ['<Item: one>'] |
|
125 ) |
|
126 self.assertQuerysetEqual( |
|
127 Item.objects.filter(Q(tags=self.t1)).filter(Q(creator__name='fred')|Q(tags=self.t2)), |
|
128 ['<Item: one>'] |
|
129 ) |
|
130 |
|
131 # Each filter call is processed "at once" against a single table, so this is |
|
132 # different from the previous example as it tries to find tags that are two |
|
133 # things at once (rather than two tags). |
|
134 self.assertQuerysetEqual( |
|
135 Item.objects.filter(Q(tags=self.t1) & Q(tags=self.t2)), |
|
136 [] |
|
137 ) |
|
138 self.assertQuerysetEqual( |
|
139 Item.objects.filter(Q(tags=self.t1), Q(creator__name='fred')|Q(tags=self.t2)), |
|
140 [] |
|
141 ) |
|
142 |
|
143 qs = Author.objects.filter(ranking__rank=2, ranking__id=self.rank1.id) |
|
144 self.assertQuerysetEqual(list(qs), ['<Author: a2>']) |
|
145 self.assertEqual(2, qs.query.count_active_tables(), 2) |
|
146 qs = Author.objects.filter(ranking__rank=2).filter(ranking__id=self.rank1.id) |
|
147 self.assertEqual(qs.query.count_active_tables(), 3) |
|
148 |
|
149 def test_ticket4464(self): |
|
150 self.assertQuerysetEqual( |
|
151 Item.objects.filter(tags=self.t1).filter(tags=self.t2), |
|
152 ['<Item: one>'] |
|
153 ) |
|
154 self.assertQuerysetEqual( |
|
155 Item.objects.filter(tags__in=[self.t1, self.t2]).distinct().order_by('name'), |
|
156 ['<Item: one>', '<Item: two>'] |
|
157 ) |
|
158 self.assertQuerysetEqual( |
|
159 Item.objects.filter(tags__in=[self.t1, self.t2]).filter(tags=self.t3), |
|
160 ['<Item: two>'] |
|
161 ) |
|
162 |
|
163 # Make sure .distinct() works with slicing (this was broken in Oracle). |
|
164 self.assertQuerysetEqual( |
|
165 Item.objects.filter(tags__in=[self.t1, self.t2]).order_by('name')[:3], |
|
166 ['<Item: one>', '<Item: one>', '<Item: two>'] |
|
167 ) |
|
168 self.assertQuerysetEqual( |
|
169 Item.objects.filter(tags__in=[self.t1, self.t2]).distinct().order_by('name')[:3], |
|
170 ['<Item: one>', '<Item: two>'] |
|
171 ) |
|
172 |
|
173 def test_tickets_2080_3592(self): |
|
174 self.assertQuerysetEqual( |
|
175 Author.objects.filter(item__name='one') | Author.objects.filter(name='a3'), |
|
176 ['<Author: a1>', '<Author: a3>'] |
|
177 ) |
|
178 self.assertQuerysetEqual( |
|
179 Author.objects.filter(Q(item__name='one') | Q(name='a3')), |
|
180 ['<Author: a1>', '<Author: a3>'] |
|
181 ) |
|
182 self.assertQuerysetEqual( |
|
183 Author.objects.filter(Q(name='a3') | Q(item__name='one')), |
|
184 ['<Author: a1>', '<Author: a3>'] |
|
185 ) |
|
186 self.assertQuerysetEqual( |
|
187 Author.objects.filter(Q(item__name='three') | Q(report__name='r3')), |
|
188 ['<Author: a2>'] |
|
189 ) |
|
190 |
|
191 def test_ticket6074(self): |
|
192 # Merging two empty result sets shouldn't leave a queryset with no constraints |
|
193 # (which would match everything). |
|
194 self.assertQuerysetEqual(Author.objects.filter(Q(id__in=[])), []) |
|
195 self.assertQuerysetEqual( |
|
196 Author.objects.filter(Q(id__in=[])|Q(id__in=[])), |
|
197 [] |
|
198 ) |
|
199 |
|
200 def test_tickets_1878_2939(self): |
|
201 self.assertEqual(Item.objects.values('creator').distinct().count(), 3) |
|
202 |
|
203 # Create something with a duplicate 'name' so that we can test multi-column |
|
204 # cases (which require some tricky SQL transformations under the covers). |
|
205 xx = Item(name='four', created=self.time1, creator=self.a2, note=self.n1) |
|
206 xx.save() |
|
207 self.assertEqual( |
|
208 Item.objects.exclude(name='two').values('creator', 'name').distinct().count(), |
|
209 4 |
|
210 ) |
|
211 self.assertEqual( |
|
212 Item.objects.exclude(name='two').extra(select={'foo': '%s'}, select_params=(1,)).values('creator', 'name', 'foo').distinct().count(), |
|
213 4 |
|
214 ) |
|
215 self.assertEqual( |
|
216 Item.objects.exclude(name='two').extra(select={'foo': '%s'}, select_params=(1,)).values('creator', 'name').distinct().count(), |
|
217 4 |
|
218 ) |
|
219 xx.delete() |
|
220 |
|
221 def test_ticket7323(self): |
|
222 self.assertEqual(Item.objects.values('creator', 'name').count(), 4) |
|
223 |
|
224 def test_ticket2253(self): |
|
225 q1 = Item.objects.order_by('name') |
|
226 q2 = Item.objects.filter(id=self.i1.id) |
|
227 self.assertQuerysetEqual( |
|
228 q1, |
|
229 ['<Item: four>', '<Item: one>', '<Item: three>', '<Item: two>'] |
|
230 ) |
|
231 self.assertQuerysetEqual(q2, ['<Item: one>']) |
|
232 self.assertQuerysetEqual( |
|
233 (q1 | q2).order_by('name'), |
|
234 ['<Item: four>', '<Item: one>', '<Item: three>', '<Item: two>'] |
|
235 ) |
|
236 self.assertQuerysetEqual((q1 & q2).order_by('name'), ['<Item: one>']) |
|
237 |
|
238 # FIXME: This is difficult to fix and very much an edge case, so punt for now. |
|
239 # This is related to the order_by() tests, below, but the old bug exhibited |
|
240 # itself here (q2 was pulling too many tables into the combined query with the |
|
241 # new ordering, but only because we have evaluated q2 already). |
|
242 # |
|
243 #self.assertEqual(len((q1 & q2).order_by('name').query.tables), 1) |
|
244 |
|
245 q1 = Item.objects.filter(tags=self.t1) |
|
246 q2 = Item.objects.filter(note=self.n3, tags=self.t2) |
|
247 q3 = Item.objects.filter(creator=self.a4) |
|
248 self.assertQuerysetEqual( |
|
249 ((q1 & q2) | q3).order_by('name'), |
|
250 ['<Item: four>', '<Item: one>'] |
|
251 ) |
|
252 |
|
253 def test_tickets_4088_4306(self): |
|
254 self.assertQuerysetEqual( |
|
255 Report.objects.filter(creator=1001), |
|
256 ['<Report: r1>'] |
|
257 ) |
|
258 self.assertQuerysetEqual( |
|
259 Report.objects.filter(creator__num=1001), |
|
260 ['<Report: r1>'] |
|
261 ) |
|
262 self.assertQuerysetEqual(Report.objects.filter(creator__id=1001), []) |
|
263 self.assertQuerysetEqual( |
|
264 Report.objects.filter(creator__id=self.a1.id), |
|
265 ['<Report: r1>'] |
|
266 ) |
|
267 self.assertQuerysetEqual( |
|
268 Report.objects.filter(creator__name='a1'), |
|
269 ['<Report: r1>'] |
|
270 ) |
|
271 |
|
272 def test_ticket4510(self): |
|
273 self.assertQuerysetEqual( |
|
274 Author.objects.filter(report__name='r1'), |
|
275 ['<Author: a1>'] |
|
276 ) |
|
277 |
|
278 def test_ticket7378(self): |
|
279 self.assertQuerysetEqual(self.a1.report_set.all(), ['<Report: r1>']) |
|
280 |
|
281 def test_tickets_5324_6704(self): |
|
282 self.assertQuerysetEqual( |
|
283 Item.objects.filter(tags__name='t4'), |
|
284 ['<Item: four>'] |
|
285 ) |
|
286 self.assertQuerysetEqual( |
|
287 Item.objects.exclude(tags__name='t4').order_by('name').distinct(), |
|
288 ['<Item: one>', '<Item: three>', '<Item: two>'] |
|
289 ) |
|
290 self.assertQuerysetEqual( |
|
291 Item.objects.exclude(tags__name='t4').order_by('name').distinct().reverse(), |
|
292 ['<Item: two>', '<Item: three>', '<Item: one>'] |
|
293 ) |
|
294 self.assertQuerysetEqual( |
|
295 Author.objects.exclude(item__name='one').distinct().order_by('name'), |
|
296 ['<Author: a2>', '<Author: a3>', '<Author: a4>'] |
|
297 ) |
|
298 |
|
299 # Excluding across a m2m relation when there is more than one related |
|
300 # object associated was problematic. |
|
301 self.assertQuerysetEqual( |
|
302 Item.objects.exclude(tags__name='t1').order_by('name'), |
|
303 ['<Item: four>', '<Item: three>'] |
|
304 ) |
|
305 self.assertQuerysetEqual( |
|
306 Item.objects.exclude(tags__name='t1').exclude(tags__name='t4'), |
|
307 ['<Item: three>'] |
|
308 ) |
|
309 |
|
310 # Excluding from a relation that cannot be NULL should not use outer joins. |
|
311 query = Item.objects.exclude(creator__in=[self.a1, self.a2]).query |
|
312 self.assertTrue(query.LOUTER not in [x[2] for x in query.alias_map.values()]) |
|
313 |
|
314 # Similarly, when one of the joins cannot possibly, ever, involve NULL |
|
315 # values (Author -> ExtraInfo, in the following), it should never be |
|
316 # promoted to a left outer join. So the following query should only |
|
317 # involve one "left outer" join (Author -> Item is 0-to-many). |
|
318 qs = Author.objects.filter(id=self.a1.id).filter(Q(extra__note=self.n1)|Q(item__note=self.n3)) |
|
319 self.assertEqual( |
|
320 len([x[2] for x in qs.query.alias_map.values() if x[2] == query.LOUTER and qs.query.alias_refcount[x[1]]]), |
|
321 1 |
|
322 ) |
|
323 |
|
324 # The previous changes shouldn't affect nullable foreign key joins. |
|
325 self.assertQuerysetEqual( |
|
326 Tag.objects.filter(parent__isnull=True).order_by('name'), |
|
327 ['<Tag: t1>'] |
|
328 ) |
|
329 self.assertQuerysetEqual( |
|
330 Tag.objects.exclude(parent__isnull=True).order_by('name'), |
|
331 ['<Tag: t2>', '<Tag: t3>', '<Tag: t4>', '<Tag: t5>'] |
|
332 ) |
|
333 self.assertQuerysetEqual( |
|
334 Tag.objects.exclude(Q(parent__name='t1') | Q(parent__isnull=True)).order_by('name'), |
|
335 ['<Tag: t4>', '<Tag: t5>'] |
|
336 ) |
|
337 self.assertQuerysetEqual( |
|
338 Tag.objects.exclude(Q(parent__isnull=True) | Q(parent__name='t1')).order_by('name'), |
|
339 ['<Tag: t4>', '<Tag: t5>'] |
|
340 ) |
|
341 self.assertQuerysetEqual( |
|
342 Tag.objects.exclude(Q(parent__parent__isnull=True)).order_by('name'), |
|
343 ['<Tag: t4>', '<Tag: t5>'] |
|
344 ) |
|
345 self.assertQuerysetEqual( |
|
346 Tag.objects.filter(~Q(parent__parent__isnull=True)).order_by('name'), |
|
347 ['<Tag: t4>', '<Tag: t5>'] |
|
348 ) |
|
349 |
|
350 def test_ticket2091(self): |
|
351 t = Tag.objects.get(name='t4') |
|
352 self.assertQuerysetEqual( |
|
353 Item.objects.filter(tags__in=[t]), |
|
354 ['<Item: four>'] |
|
355 ) |
|
356 |
|
357 def test_heterogeneous_qs_combination(self): |
|
358 # Combining querysets built on different models should behave in a well-defined |
|
359 # fashion. We raise an error. |
|
360 self.assertRaisesMessage( |
|
361 AssertionError, |
|
362 'Cannot combine queries on two different base models.', |
|
363 lambda: Author.objects.all() & Tag.objects.all() |
|
364 ) |
|
365 self.assertRaisesMessage( |
|
366 AssertionError, |
|
367 'Cannot combine queries on two different base models.', |
|
368 lambda: Author.objects.all() | Tag.objects.all() |
|
369 ) |
|
370 |
|
371 def test_ticket3141(self): |
|
372 self.assertEqual(Author.objects.extra(select={'foo': '1'}).count(), 4) |
|
373 self.assertEqual( |
|
374 Author.objects.extra(select={'foo': '%s'}, select_params=(1,)).count(), |
|
375 4 |
|
376 ) |
|
377 |
|
378 def test_ticket2400(self): |
|
379 self.assertQuerysetEqual( |
|
380 Author.objects.filter(item__isnull=True), |
|
381 ['<Author: a3>'] |
|
382 ) |
|
383 self.assertQuerysetEqual( |
|
384 Tag.objects.filter(item__isnull=True), |
|
385 ['<Tag: t5>'] |
|
386 ) |
|
387 |
|
388 def test_ticket2496(self): |
|
389 self.assertQuerysetEqual( |
|
390 Item.objects.extra(tables=['queries_author']).select_related().order_by('name')[:1], |
|
391 ['<Item: four>'] |
|
392 ) |
|
393 |
|
394 def test_tickets_2076_7256(self): |
|
395 # Ordering on related tables should be possible, even if the table is |
|
396 # not otherwise involved. |
|
397 self.assertQuerysetEqual( |
|
398 Item.objects.order_by('note__note', 'name'), |
|
399 ['<Item: two>', '<Item: four>', '<Item: one>', '<Item: three>'] |
|
400 ) |
|
401 |
|
402 # Ordering on a related field should use the remote model's default |
|
403 # ordering as a final step. |
|
404 self.assertQuerysetEqual( |
|
405 Author.objects.order_by('extra', '-name'), |
|
406 ['<Author: a2>', '<Author: a1>', '<Author: a4>', '<Author: a3>'] |
|
407 ) |
|
408 |
|
409 # Using remote model default ordering can span multiple models (in this |
|
410 # case, Cover is ordered by Item's default, which uses Note's default). |
|
411 self.assertQuerysetEqual( |
|
412 Cover.objects.all(), |
|
413 ['<Cover: first>', '<Cover: second>'] |
|
414 ) |
|
415 |
|
416 # If the remote model does not have a default ordering, we order by its 'id' |
|
417 # field. |
|
418 self.assertQuerysetEqual( |
|
419 Item.objects.order_by('creator', 'name'), |
|
420 ['<Item: one>', '<Item: three>', '<Item: two>', '<Item: four>'] |
|
421 ) |
|
422 |
|
423 # Ordering by a many-valued attribute (e.g. a many-to-many or reverse |
|
424 # ForeignKey) is legal, but the results might not make sense. That |
|
425 # isn't Django's problem. Garbage in, garbage out. |
|
426 self.assertQuerysetEqual( |
|
427 Item.objects.filter(tags__isnull=False).order_by('tags', 'id'), |
|
428 ['<Item: one>', '<Item: two>', '<Item: one>', '<Item: two>', '<Item: four>'] |
|
429 ) |
|
430 |
|
431 # If we replace the default ordering, Django adjusts the required |
|
432 # tables automatically. Item normally requires a join with Note to do |
|
433 # the default ordering, but that isn't needed here. |
|
434 qs = Item.objects.order_by('name') |
|
435 self.assertQuerysetEqual( |
|
436 qs, |
|
437 ['<Item: four>', '<Item: one>', '<Item: three>', '<Item: two>'] |
|
438 ) |
|
439 self.assertEqual(len(qs.query.tables), 1) |
|
440 |
|
441 def test_tickets_2874_3002(self): |
|
442 qs = Item.objects.select_related().order_by('note__note', 'name') |
|
443 self.assertQuerysetEqual( |
|
444 qs, |
|
445 ['<Item: two>', '<Item: four>', '<Item: one>', '<Item: three>'] |
|
446 ) |
|
447 |
|
448 # This is also a good select_related() test because there are multiple |
|
449 # Note entries in the SQL. The two Note items should be different. |
|
450 self.assertTrue(repr(qs[0].note), '<Note: n2>') |
|
451 self.assertEqual(repr(qs[0].creator.extra.note), '<Note: n1>') |
|
452 |
|
453 def test_ticket3037(self): |
|
454 self.assertQuerysetEqual( |
|
455 Item.objects.filter(Q(creator__name='a3', name='two')|Q(creator__name='a4', name='four')), |
|
456 ['<Item: four>'] |
|
457 ) |
|
458 |
|
459 def test_tickets_5321_7070(self): |
|
460 # Ordering columns must be included in the output columns. Note that |
|
461 # this means results that might otherwise be distinct are not (if there |
|
462 # are multiple values in the ordering cols), as in this example. This |
|
463 # isn't a bug; it's a warning to be careful with the selection of |
|
464 # ordering columns. |
|
465 self.assertValueQuerysetEqual( |
|
466 Note.objects.values('misc').distinct().order_by('note', '-misc'), |
|
467 [{'misc': u'foo'}, {'misc': u'bar'}, {'misc': u'foo'}] |
|
468 ) |
|
469 |
|
470 def test_ticket4358(self): |
|
471 # If you don't pass any fields to values(), relation fields are |
|
472 # returned as "foo_id" keys, not "foo". For consistency, you should be |
|
473 # able to pass "foo_id" in the fields list and have it work, too. We |
|
474 # actually allow both "foo" and "foo_id". |
|
475 |
|
476 # The *_id version is returned by default. |
|
477 self.assertTrue('note_id' in ExtraInfo.objects.values()[0]) |
|
478 |
|
479 # You can also pass it in explicitly. |
|
480 self.assertValueQuerysetEqual( |
|
481 ExtraInfo.objects.values('note_id'), |
|
482 [{'note_id': 1}, {'note_id': 2}] |
|
483 ) |
|
484 |
|
485 # ...or use the field name. |
|
486 self.assertValueQuerysetEqual( |
|
487 ExtraInfo.objects.values('note'), |
|
488 [{'note': 1}, {'note': 2}] |
|
489 ) |
|
490 |
|
491 def test_ticket2902(self): |
|
492 # Parameters can be given to extra_select, *if* you use a SortedDict. |
|
493 |
|
494 # (First we need to know which order the keys fall in "naturally" on |
|
495 # your system, so we can put things in the wrong way around from |
|
496 # normal. A normal dict would thus fail.) |
|
497 s = [('a', '%s'), ('b', '%s')] |
|
498 params = ['one', 'two'] |
|
499 if {'a': 1, 'b': 2}.keys() == ['a', 'b']: |
|
500 s.reverse() |
|
501 params.reverse() |
|
502 |
|
503 # This slightly odd comparison works around the fact that PostgreSQL will |
|
504 # return 'one' and 'two' as strings, not Unicode objects. It's a side-effect of |
|
505 # using constants here and not a real concern. |
|
506 d = Item.objects.extra(select=SortedDict(s), select_params=params).values('a', 'b')[0] |
|
507 self.assertEqual(d, {'a': u'one', 'b': u'two'}) |
|
508 |
|
509 # Order by the number of tags attached to an item. |
|
510 l = Item.objects.extra(select={'count': 'select count(*) from queries_item_tags where queries_item_tags.item_id = queries_item.id'}).order_by('-count') |
|
511 self.assertEqual([o.count for o in l], [2, 2, 1, 0]) |
|
512 |
|
513 def test_ticket6154(self): |
|
514 # Multiple filter statements are joined using "AND" all the time. |
|
515 |
|
516 self.assertQuerysetEqual( |
|
517 Author.objects.filter(id=self.a1.id).filter(Q(extra__note=self.n1)|Q(item__note=self.n3)), |
|
518 ['<Author: a1>'] |
|
519 ) |
|
520 self.assertQuerysetEqual( |
|
521 Author.objects.filter(Q(extra__note=self.n1)|Q(item__note=self.n3)).filter(id=self.a1.id), |
|
522 ['<Author: a1>'] |
|
523 ) |
|
524 |
|
525 def test_ticket6981(self): |
|
526 self.assertQuerysetEqual( |
|
527 Tag.objects.select_related('parent').order_by('name'), |
|
528 ['<Tag: t1>', '<Tag: t2>', '<Tag: t3>', '<Tag: t4>', '<Tag: t5>'] |
|
529 ) |
|
530 |
|
531 def test_ticket9926(self): |
|
532 self.assertQuerysetEqual( |
|
533 Tag.objects.select_related("parent", "category").order_by('name'), |
|
534 ['<Tag: t1>', '<Tag: t2>', '<Tag: t3>', '<Tag: t4>', '<Tag: t5>'] |
|
535 ) |
|
536 self.assertQuerysetEqual( |
|
537 Tag.objects.select_related('parent', "parent__category").order_by('name'), |
|
538 ['<Tag: t1>', '<Tag: t2>', '<Tag: t3>', '<Tag: t4>', '<Tag: t5>'] |
|
539 ) |
|
540 |
|
541 def test_tickets_6180_6203(self): |
|
542 # Dates with limits and/or counts |
|
543 self.assertEqual(Item.objects.count(), 4) |
|
544 self.assertEqual(Item.objects.dates('created', 'month').count(), 1) |
|
545 self.assertEqual(Item.objects.dates('created', 'day').count(), 2) |
|
546 self.assertEqual(len(Item.objects.dates('created', 'day')), 2) |
|
547 self.assertEqual(Item.objects.dates('created', 'day')[0], datetime.datetime(2007, 12, 19, 0, 0)) |
|
548 |
|
549 def test_tickets_7087_12242(self): |
|
550 # Dates with extra select columns |
|
551 self.assertQuerysetEqual( |
|
552 Item.objects.dates('created', 'day').extra(select={'a': 1}), |
|
553 ['datetime.datetime(2007, 12, 19, 0, 0)', 'datetime.datetime(2007, 12, 20, 0, 0)'] |
|
554 ) |
|
555 self.assertQuerysetEqual( |
|
556 Item.objects.extra(select={'a': 1}).dates('created', 'day'), |
|
557 ['datetime.datetime(2007, 12, 19, 0, 0)', 'datetime.datetime(2007, 12, 20, 0, 0)'] |
|
558 ) |
|
559 |
|
560 name="one" |
|
561 self.assertQuerysetEqual( |
|
562 Item.objects.dates('created', 'day').extra(where=['name=%s'], params=[name]), |
|
563 ['datetime.datetime(2007, 12, 19, 0, 0)'] |
|
564 ) |
|
565 |
|
566 self.assertQuerysetEqual( |
|
567 Item.objects.extra(where=['name=%s'], params=[name]).dates('created', 'day'), |
|
568 ['datetime.datetime(2007, 12, 19, 0, 0)'] |
|
569 ) |
|
570 |
|
571 def test_ticket7155(self): |
|
572 # Nullable dates |
|
573 self.assertQuerysetEqual( |
|
574 Item.objects.dates('modified', 'day'), |
|
575 ['datetime.datetime(2007, 12, 19, 0, 0)'] |
|
576 ) |
|
577 |
|
578 def test_ticket7098(self): |
|
579 # Make sure semi-deprecated ordering by related models syntax still |
|
580 # works. |
|
581 self.assertValueQuerysetEqual( |
|
582 Item.objects.values('note__note').order_by('queries_note.note', 'id'), |
|
583 [{'note__note': u'n2'}, {'note__note': u'n3'}, {'note__note': u'n3'}, {'note__note': u'n3'}] |
|
584 ) |
|
585 |
|
586 def test_ticket7096(self): |
|
587 # Make sure exclude() with multiple conditions continues to work. |
|
588 self.assertQuerysetEqual( |
|
589 Tag.objects.filter(parent=self.t1, name='t3').order_by('name'), |
|
590 ['<Tag: t3>'] |
|
591 ) |
|
592 self.assertQuerysetEqual( |
|
593 Tag.objects.exclude(parent=self.t1, name='t3').order_by('name'), |
|
594 ['<Tag: t1>', '<Tag: t2>', '<Tag: t4>', '<Tag: t5>'] |
|
595 ) |
|
596 self.assertQuerysetEqual( |
|
597 Item.objects.exclude(tags__name='t1', name='one').order_by('name').distinct(), |
|
598 ['<Item: four>', '<Item: three>', '<Item: two>'] |
|
599 ) |
|
600 self.assertQuerysetEqual( |
|
601 Item.objects.filter(name__in=['three', 'four']).exclude(tags__name='t1').order_by('name'), |
|
602 ['<Item: four>', '<Item: three>'] |
|
603 ) |
|
604 |
|
605 # More twisted cases, involving nested negations. |
|
606 self.assertQuerysetEqual( |
|
607 Item.objects.exclude(~Q(tags__name='t1', name='one')), |
|
608 ['<Item: one>'] |
|
609 ) |
|
610 self.assertQuerysetEqual( |
|
611 Item.objects.filter(~Q(tags__name='t1', name='one'), name='two'), |
|
612 ['<Item: two>'] |
|
613 ) |
|
614 self.assertQuerysetEqual( |
|
615 Item.objects.exclude(~Q(tags__name='t1', name='one'), name='two'), |
|
616 ['<Item: four>', '<Item: one>', '<Item: three>'] |
|
617 ) |
|
618 |
|
619 def test_tickets_7204_7506(self): |
|
620 # Make sure querysets with related fields can be pickled. If this |
|
621 # doesn't crash, it's a Good Thing. |
|
622 pickle.dumps(Item.objects.all()) |
|
623 |
|
624 def test_ticket7813(self): |
|
625 # We should also be able to pickle things that use select_related(). |
|
626 # The only tricky thing here is to ensure that we do the related |
|
627 # selections properly after unpickling. |
|
628 qs = Item.objects.select_related() |
|
629 query = qs.query.get_compiler(qs.db).as_sql()[0] |
|
630 query2 = pickle.loads(pickle.dumps(qs.query)) |
|
631 self.assertEqual( |
|
632 query2.get_compiler(qs.db).as_sql()[0], |
|
633 query |
|
634 ) |
|
635 |
|
636 def test_deferred_load_qs_pickling(self): |
|
637 # Check pickling of deferred-loading querysets |
|
638 qs = Item.objects.defer('name', 'creator') |
|
639 q2 = pickle.loads(pickle.dumps(qs)) |
|
640 self.assertEqual(list(qs), list(q2)) |
|
641 q3 = pickle.loads(pickle.dumps(qs, pickle.HIGHEST_PROTOCOL)) |
|
642 self.assertEqual(list(qs), list(q3)) |
|
643 |
|
644 def test_ticket7277(self): |
|
645 self.assertQuerysetEqual( |
|
646 self.n1.annotation_set.filter(Q(tag=self.t5) | Q(tag__children=self.t5) | Q(tag__children__children=self.t5)), |
|
647 ['<Annotation: a1>'] |
|
648 ) |
|
649 |
|
650 def test_tickets_7448_7707(self): |
|
651 # Complex objects should be converted to strings before being used in |
|
652 # lookups. |
|
653 self.assertQuerysetEqual( |
|
654 Item.objects.filter(created__in=[self.time1, self.time2]), |
|
655 ['<Item: one>', '<Item: two>'] |
|
656 ) |
|
657 |
|
658 def test_ticket7235(self): |
|
659 # An EmptyQuerySet should not raise exceptions if it is filtered. |
|
660 q = EmptyQuerySet() |
|
661 self.assertQuerysetEqual(q.all(), []) |
|
662 self.assertQuerysetEqual(q.filter(x=10), []) |
|
663 self.assertQuerysetEqual(q.exclude(y=3), []) |
|
664 self.assertQuerysetEqual(q.complex_filter({'pk': 1}), []) |
|
665 self.assertQuerysetEqual(q.select_related('spam', 'eggs'), []) |
|
666 self.assertQuerysetEqual(q.annotate(Count('eggs')), []) |
|
667 self.assertQuerysetEqual(q.order_by('-pub_date', 'headline'), []) |
|
668 self.assertQuerysetEqual(q.distinct(), []) |
|
669 self.assertQuerysetEqual( |
|
670 q.extra(select={'is_recent': "pub_date > '2006-01-01'"}), |
|
671 [] |
|
672 ) |
|
673 q.query.low_mark = 1 |
|
674 self.assertRaisesMessage( |
|
675 AssertionError, |
|
676 'Cannot change a query once a slice has been taken', |
|
677 q.extra, select={'is_recent': "pub_date > '2006-01-01'"} |
|
678 ) |
|
679 self.assertQuerysetEqual(q.reverse(), []) |
|
680 self.assertQuerysetEqual(q.defer('spam', 'eggs'), []) |
|
681 self.assertQuerysetEqual(q.only('spam', 'eggs'), []) |
|
682 |
|
683 def test_ticket7791(self): |
|
684 # There were "issues" when ordering and distinct-ing on fields related |
|
685 # via ForeignKeys. |
|
686 self.assertEqual( |
|
687 len(Note.objects.order_by('extrainfo__info').distinct()), |
|
688 3 |
|
689 ) |
|
690 |
|
691 # Pickling of DateQuerySets used to fail |
|
692 qs = Item.objects.dates('created', 'month') |
|
693 _ = pickle.loads(pickle.dumps(qs)) |
|
694 |
|
695 def test_ticket9997(self): |
|
696 # If a ValuesList or Values queryset is passed as an inner query, we |
|
697 # make sure it's only requesting a single value and use that as the |
|
698 # thing to select. |
|
699 self.assertQuerysetEqual( |
|
700 Tag.objects.filter(name__in=Tag.objects.filter(parent=self.t1).values('name')), |
|
701 ['<Tag: t2>', '<Tag: t3>'] |
|
702 ) |
|
703 |
|
704 # Multi-valued values() and values_list() querysets should raise errors. |
|
705 self.assertRaisesMessage( |
|
706 TypeError, |
|
707 'Cannot use a multi-field ValuesQuerySet as a filter value.', |
|
708 lambda: Tag.objects.filter(name__in=Tag.objects.filter(parent=self.t1).values('name', 'id')) |
|
709 ) |
|
710 self.assertRaisesMessage( |
|
711 TypeError, |
|
712 'Cannot use a multi-field ValuesListQuerySet as a filter value.', |
|
713 lambda: Tag.objects.filter(name__in=Tag.objects.filter(parent=self.t1).values_list('name', 'id')) |
|
714 ) |
|
715 |
|
716 def test_ticket9985(self): |
|
717 # qs.values_list(...).values(...) combinations should work. |
|
718 self.assertValueQuerysetEqual( |
|
719 Note.objects.values_list("note", flat=True).values("id").order_by("id"), |
|
720 [{'id': 1}, {'id': 2}, {'id': 3}] |
|
721 ) |
|
722 self.assertQuerysetEqual( |
|
723 Annotation.objects.filter(notes__in=Note.objects.filter(note="n1").values_list('note').values('id')), |
|
724 ['<Annotation: a1>'] |
|
725 ) |
|
726 |
|
727 def test_ticket10205(self): |
|
728 # When bailing out early because of an empty "__in" filter, we need |
|
729 # to set things up correctly internally so that subqueries can continue properly. |
|
730 self.assertEqual(Tag.objects.filter(name__in=()).update(name="foo"), 0) |
|
731 |
|
732 def test_ticket10432(self): |
|
733 # Testing an empty "__in" filter with a generator as the value. |
|
734 def f(): |
|
735 return iter([]) |
|
736 n_obj = Note.objects.all()[0] |
|
737 def g(): |
|
738 for i in [n_obj.pk]: |
|
739 yield i |
|
740 self.assertQuerysetEqual(Note.objects.filter(pk__in=f()), []) |
|
741 self.assertEqual(list(Note.objects.filter(pk__in=g())), [n_obj]) |
|
742 |
|
743 def test_ticket10742(self): |
|
744 # Queries used in an __in clause don't execute subqueries |
|
745 |
|
746 subq = Author.objects.filter(num__lt=3000) |
|
747 qs = Author.objects.filter(pk__in=subq) |
|
748 self.assertQuerysetEqual(qs, ['<Author: a1>', '<Author: a2>']) |
|
749 |
|
750 # The subquery result cache should not be populated |
|
751 self.assertTrue(subq._result_cache is None) |
|
752 |
|
753 subq = Author.objects.filter(num__lt=3000) |
|
754 qs = Author.objects.exclude(pk__in=subq) |
|
755 self.assertQuerysetEqual(qs, ['<Author: a3>', '<Author: a4>']) |
|
756 |
|
757 # The subquery result cache should not be populated |
|
758 self.assertTrue(subq._result_cache is None) |
|
759 |
|
760 subq = Author.objects.filter(num__lt=3000) |
|
761 self.assertQuerysetEqual( |
|
762 Author.objects.filter(Q(pk__in=subq) & Q(name='a1')), |
|
763 ['<Author: a1>'] |
|
764 ) |
|
765 |
|
766 # The subquery result cache should not be populated |
|
767 self.assertTrue(subq._result_cache is None) |
|
768 |
|
769 def test_ticket7076(self): |
|
770 # Excluding shouldn't eliminate NULL entries. |
|
771 self.assertQuerysetEqual( |
|
772 Item.objects.exclude(modified=self.time1).order_by('name'), |
|
773 ['<Item: four>', '<Item: three>', '<Item: two>'] |
|
774 ) |
|
775 self.assertQuerysetEqual( |
|
776 Tag.objects.exclude(parent__name=self.t1.name), |
|
777 ['<Tag: t1>', '<Tag: t4>', '<Tag: t5>'] |
|
778 ) |
|
779 |
|
780 def test_ticket7181(self): |
|
781 # Ordering by related tables should accomodate nullable fields (this |
|
782 # test is a little tricky, since NULL ordering is database dependent. |
|
783 # Instead, we just count the number of results). |
|
784 self.assertEqual(len(Tag.objects.order_by('parent__name')), 5) |
|
785 |
|
786 # Empty querysets can be merged with others. |
|
787 self.assertQuerysetEqual( |
|
788 Note.objects.none() | Note.objects.all(), |
|
789 ['<Note: n1>', '<Note: n2>', '<Note: n3>'] |
|
790 ) |
|
791 self.assertQuerysetEqual( |
|
792 Note.objects.all() | Note.objects.none(), |
|
793 ['<Note: n1>', '<Note: n2>', '<Note: n3>'] |
|
794 ) |
|
795 self.assertQuerysetEqual(Note.objects.none() & Note.objects.all(), []) |
|
796 self.assertQuerysetEqual(Note.objects.all() & Note.objects.none(), []) |
|
797 |
|
798 def test_ticket9411(self): |
|
799 # Make sure bump_prefix() (an internal Query method) doesn't (re-)break. It's |
|
800 # sufficient that this query runs without error. |
|
801 qs = Tag.objects.values_list('id', flat=True).order_by('id') |
|
802 qs.query.bump_prefix() |
|
803 first = qs[0] |
|
804 self.assertEqual(list(qs), range(first, first+5)) |
|
805 |
|
806 def test_ticket8439(self): |
|
807 # Complex combinations of conjunctions, disjunctions and nullable |
|
808 # relations. |
|
809 self.assertQuerysetEqual( |
|
810 Author.objects.filter(Q(item__note__extrainfo=self.e2)|Q(report=self.r1, name='xyz')), |
|
811 ['<Author: a2>'] |
|
812 ) |
|
813 self.assertQuerysetEqual( |
|
814 Author.objects.filter(Q(report=self.r1, name='xyz')|Q(item__note__extrainfo=self.e2)), |
|
815 ['<Author: a2>'] |
|
816 ) |
|
817 self.assertQuerysetEqual( |
|
818 Annotation.objects.filter(Q(tag__parent=self.t1)|Q(notes__note='n1', name='a1')), |
|
819 ['<Annotation: a1>'] |
|
820 ) |
|
821 xx = ExtraInfo.objects.create(info='xx', note=self.n3) |
|
822 self.assertQuerysetEqual( |
|
823 Note.objects.filter(Q(extrainfo__author=self.a1)|Q(extrainfo=xx)), |
|
824 ['<Note: n1>', '<Note: n3>'] |
|
825 ) |
|
826 xx.delete() |
|
827 q = Note.objects.filter(Q(extrainfo__author=self.a1)|Q(extrainfo=xx)).query |
|
828 self.assertEqual( |
|
829 len([x[2] for x in q.alias_map.values() if x[2] == q.LOUTER and q.alias_refcount[x[1]]]), |
|
830 1 |
|
831 ) |
|
832 |
|
833 |
|
834 class Queries2Tests(TestCase): |
|
835 def setUp(self): |
|
836 Number.objects.create(num=4) |
|
837 Number.objects.create(num=8) |
|
838 Number.objects.create(num=12) |
|
839 |
|
840 def test_ticket4289(self): |
|
841 # A slight variation on the restricting the filtering choices by the |
|
842 # lookup constraints. |
|
843 self.assertQuerysetEqual(Number.objects.filter(num__lt=4), []) |
|
844 self.assertQuerysetEqual(Number.objects.filter(num__gt=8, num__lt=12), []) |
|
845 self.assertQuerysetEqual( |
|
846 Number.objects.filter(num__gt=8, num__lt=13), |
|
847 ['<Number: 12>'] |
|
848 ) |
|
849 self.assertQuerysetEqual( |
|
850 Number.objects.filter(Q(num__lt=4) | Q(num__gt=8, num__lt=12)), |
|
851 [] |
|
852 ) |
|
853 self.assertQuerysetEqual( |
|
854 Number.objects.filter(Q(num__gt=8, num__lt=12) | Q(num__lt=4)), |
|
855 [] |
|
856 ) |
|
857 self.assertQuerysetEqual( |
|
858 Number.objects.filter(Q(num__gt=8) & Q(num__lt=12) | Q(num__lt=4)), |
|
859 [] |
|
860 ) |
|
861 self.assertQuerysetEqual( |
|
862 Number.objects.filter(Q(num__gt=7) & Q(num__lt=12) | Q(num__lt=4)), |
|
863 ['<Number: 8>'] |
|
864 ) |
|
865 |
|
866 def test_ticket12239(self): |
|
867 # Float was being rounded to integer on gte queries on integer field. Tests |
|
868 # show that gt, lt, gte, and lte work as desired. Note that the fix changes |
|
869 # get_prep_lookup for gte and lt queries only. |
|
870 self.assertQuerysetEqual( |
|
871 Number.objects.filter(num__gt=11.9), |
|
872 ['<Number: 12>'] |
|
873 ) |
|
874 self.assertQuerysetEqual(Number.objects.filter(num__gt=12), []) |
|
875 self.assertQuerysetEqual(Number.objects.filter(num__gt=12.0), []) |
|
876 self.assertQuerysetEqual(Number.objects.filter(num__gt=12.1), []) |
|
877 self.assertQuerysetEqual( |
|
878 Number.objects.filter(num__lt=12), |
|
879 ['<Number: 4>', '<Number: 8>'] |
|
880 ) |
|
881 self.assertQuerysetEqual( |
|
882 Number.objects.filter(num__lt=12.0), |
|
883 ['<Number: 4>', '<Number: 8>'] |
|
884 ) |
|
885 self.assertQuerysetEqual( |
|
886 Number.objects.filter(num__lt=12.1), |
|
887 ['<Number: 4>', '<Number: 8>', '<Number: 12>'] |
|
888 ) |
|
889 self.assertQuerysetEqual( |
|
890 Number.objects.filter(num__gte=11.9), |
|
891 ['<Number: 12>'] |
|
892 ) |
|
893 self.assertQuerysetEqual( |
|
894 Number.objects.filter(num__gte=12), |
|
895 ['<Number: 12>'] |
|
896 ) |
|
897 self.assertQuerysetEqual( |
|
898 Number.objects.filter(num__gte=12.0), |
|
899 ['<Number: 12>'] |
|
900 ) |
|
901 self.assertQuerysetEqual(Number.objects.filter(num__gte=12.1), []) |
|
902 self.assertQuerysetEqual(Number.objects.filter(num__gte=12.9), []) |
|
903 self.assertQuerysetEqual( |
|
904 Number.objects.filter(num__lte=11.9), |
|
905 ['<Number: 4>', '<Number: 8>'] |
|
906 ) |
|
907 self.assertQuerysetEqual( |
|
908 Number.objects.filter(num__lte=12), |
|
909 ['<Number: 4>', '<Number: 8>', '<Number: 12>'] |
|
910 ) |
|
911 self.assertQuerysetEqual( |
|
912 Number.objects.filter(num__lte=12.0), |
|
913 ['<Number: 4>', '<Number: 8>', '<Number: 12>'] |
|
914 ) |
|
915 self.assertQuerysetEqual( |
|
916 Number.objects.filter(num__lte=12.1), |
|
917 ['<Number: 4>', '<Number: 8>', '<Number: 12>'] |
|
918 ) |
|
919 self.assertQuerysetEqual( |
|
920 Number.objects.filter(num__lte=12.9), |
|
921 ['<Number: 4>', '<Number: 8>', '<Number: 12>'] |
|
922 ) |
|
923 |
|
924 def test_ticket7411(self): |
|
925 # Saving to db must work even with partially read result set in another |
|
926 # cursor. |
|
927 for num in range(2 * ITER_CHUNK_SIZE + 1): |
|
928 _ = Number.objects.create(num=num) |
|
929 |
|
930 for i, obj in enumerate(Number.objects.all()): |
|
931 obj.save() |
|
932 if i > 10: break |
|
933 |
|
934 def test_ticket7759(self): |
|
935 # Count should work with a partially read result set. |
|
936 count = Number.objects.count() |
|
937 qs = Number.objects.all() |
|
938 def run(): |
|
939 for obj in qs: |
|
940 return qs.count() == count |
|
941 self.assertTrue(run()) |
|
942 |
|
943 |
|
944 class Queries3Tests(BaseQuerysetTest): |
|
945 def test_ticket7107(self): |
|
946 # This shouldn't create an infinite loop. |
|
947 self.assertQuerysetEqual(Valid.objects.all(), []) |
|
948 |
|
949 def test_ticket8683(self): |
|
950 # Raise proper error when a DateQuerySet gets passed a wrong type of |
|
951 # field |
|
952 self.assertRaisesMessage( |
|
953 AssertionError, |
|
954 "'name' isn't a DateField.", |
|
955 Item.objects.dates, 'name', 'month' |
|
956 ) |
|
957 |
|
958 class Queries4Tests(BaseQuerysetTest): |
|
959 def setUp(self): |
|
960 generic = NamedCategory.objects.create(name="Generic") |
|
961 self.t1 = Tag.objects.create(name='t1', category=generic) |
|
962 |
|
963 n1 = Note.objects.create(note='n1', misc='foo', id=1) |
|
964 n2 = Note.objects.create(note='n2', misc='bar', id=2) |
|
965 |
|
966 e1 = ExtraInfo.objects.create(info='e1', note=n1) |
|
967 e2 = ExtraInfo.objects.create(info='e2', note=n2) |
|
968 |
|
969 a1 = Author.objects.create(name='a1', num=1001, extra=e1) |
|
970 a3 = Author.objects.create(name='a3', num=3003, extra=e2) |
|
971 |
|
972 Report.objects.create(name='r1', creator=a1) |
|
973 Report.objects.create(name='r2', creator=a3) |
|
974 Report.objects.create(name='r3') |
|
975 |
|
976 def test_ticket7095(self): |
|
977 # Updates that are filtered on the model being updated are somewhat |
|
978 # tricky in MySQL. This exercises that case. |
|
979 ManagedModel.objects.create(data='mm1', tag=self.t1, public=True) |
|
980 self.assertEqual(ManagedModel.objects.update(data='mm'), 1) |
|
981 |
|
982 # A values() or values_list() query across joined models must use outer |
|
983 # joins appropriately. |
|
984 # Note: In Oracle, we expect a null CharField to return u'' instead of |
|
985 # None. |
|
986 if connection.features.interprets_empty_strings_as_nulls: |
|
987 expected_null_charfield_repr = u'' |
|
988 else: |
|
989 expected_null_charfield_repr = None |
|
990 self.assertValueQuerysetEqual( |
|
991 Report.objects.values_list("creator__extra__info", flat=True).order_by("name"), |
|
992 [u'e1', u'e2', expected_null_charfield_repr], |
|
993 ) |
|
994 |
|
995 # Similarly for select_related(), joins beyond an initial nullable join |
|
996 # must use outer joins so that all results are included. |
|
997 self.assertQuerysetEqual( |
|
998 Report.objects.select_related("creator", "creator__extra").order_by("name"), |
|
999 ['<Report: r1>', '<Report: r2>', '<Report: r3>'] |
|
1000 ) |
|
1001 |
|
1002 # When there are multiple paths to a table from another table, we have |
|
1003 # to be careful not to accidentally reuse an inappropriate join when |
|
1004 # using select_related(). We used to return the parent's Detail record |
|
1005 # here by mistake. |
|
1006 |
|
1007 d1 = Detail.objects.create(data="d1") |
|
1008 d2 = Detail.objects.create(data="d2") |
|
1009 m1 = Member.objects.create(name="m1", details=d1) |
|
1010 m2 = Member.objects.create(name="m2", details=d2) |
|
1011 Child.objects.create(person=m2, parent=m1) |
|
1012 obj = m1.children.select_related("person__details")[0] |
|
1013 self.assertEqual(obj.person.details.data, u'd2') |
|
1014 |
|
1015 def test_order_by_resetting(self): |
|
1016 # Calling order_by() with no parameters removes any existing ordering on the |
|
1017 # model. But it should still be possible to add new ordering after that. |
|
1018 qs = Author.objects.order_by().order_by('name') |
|
1019 self.assertTrue('ORDER BY' in qs.query.get_compiler(qs.db).as_sql()[0]) |
|
1020 |
|
1021 def test_ticket10181(self): |
|
1022 # Avoid raising an EmptyResultSet if an inner query is probably |
|
1023 # empty (and hence, not executed). |
|
1024 self.assertQuerysetEqual( |
|
1025 Tag.objects.filter(id__in=Tag.objects.filter(id__in=[])), |
|
1026 [] |
|
1027 ) |
|
1028 |
|
1029 |
|
1030 class Queries5Tests(TestCase): |
|
1031 def setUp(self): |
|
1032 # Ordering by 'rank' gives us rank2, rank1, rank3. Ordering by the Meta.ordering |
|
1033 # will be rank3, rank2, rank1. |
|
1034 n1 = Note.objects.create(note='n1', misc='foo', id=1) |
|
1035 n2 = Note.objects.create(note='n2', misc='bar', id=2) |
|
1036 e1 = ExtraInfo.objects.create(info='e1', note=n1) |
|
1037 e2 = ExtraInfo.objects.create(info='e2', note=n2) |
|
1038 a1 = Author.objects.create(name='a1', num=1001, extra=e1) |
|
1039 a2 = Author.objects.create(name='a2', num=2002, extra=e1) |
|
1040 a3 = Author.objects.create(name='a3', num=3003, extra=e2) |
|
1041 self.rank1 = Ranking.objects.create(rank=2, author=a2) |
|
1042 Ranking.objects.create(rank=1, author=a3) |
|
1043 Ranking.objects.create(rank=3, author=a1) |
|
1044 |
|
1045 def test_ordering(self): |
|
1046 # Cross model ordering is possible in Meta, too. |
|
1047 self.assertQuerysetEqual( |
|
1048 Ranking.objects.all(), |
|
1049 ['<Ranking: 3: a1>', '<Ranking: 2: a2>', '<Ranking: 1: a3>'] |
|
1050 ) |
|
1051 self.assertQuerysetEqual( |
|
1052 Ranking.objects.all().order_by('rank'), |
|
1053 ['<Ranking: 1: a3>', '<Ranking: 2: a2>', '<Ranking: 3: a1>'] |
|
1054 ) |
|
1055 |
|
1056 |
|
1057 # Ordering of extra() pieces is possible, too and you can mix extra |
|
1058 # fields and model fields in the ordering. |
|
1059 self.assertQuerysetEqual( |
|
1060 Ranking.objects.extra(tables=['django_site'], order_by=['-django_site.id', 'rank']), |
|
1061 ['<Ranking: 1: a3>', '<Ranking: 2: a2>', '<Ranking: 3: a1>'] |
|
1062 ) |
|
1063 |
|
1064 qs = Ranking.objects.extra(select={'good': 'case when rank > 2 then 1 else 0 end'}) |
|
1065 self.assertEqual( |
|
1066 [o.good for o in qs.extra(order_by=('-good',))], |
|
1067 [True, False, False] |
|
1068 ) |
|
1069 self.assertQuerysetEqual( |
|
1070 qs.extra(order_by=('-good', 'id')), |
|
1071 ['<Ranking: 3: a1>', '<Ranking: 2: a2>', '<Ranking: 1: a3>'] |
|
1072 ) |
|
1073 |
|
1074 # Despite having some extra aliases in the query, we can still omit |
|
1075 # them in a values() query. |
|
1076 dicts = qs.values('id', 'rank').order_by('id') |
|
1077 self.assertEqual( |
|
1078 [d.items()[1] for d in dicts], |
|
1079 [('rank', 2), ('rank', 1), ('rank', 3)] |
|
1080 ) |
|
1081 |
|
1082 def test_ticket7256(self): |
|
1083 # An empty values() call includes all aliases, including those from an |
|
1084 # extra() |
|
1085 qs = Ranking.objects.extra(select={'good': 'case when rank > 2 then 1 else 0 end'}) |
|
1086 dicts = qs.values().order_by('id') |
|
1087 for d in dicts: del d['id']; del d['author_id'] |
|
1088 self.assertEqual( |
|
1089 [sorted(d.items()) for d in dicts], |
|
1090 [[('good', 0), ('rank', 2)], [('good', 0), ('rank', 1)], [('good', 1), ('rank', 3)]] |
|
1091 ) |
|
1092 |
|
1093 def test_ticket7045(self): |
|
1094 # Extra tables used to crash SQL construction on the second use. |
|
1095 qs = Ranking.objects.extra(tables=['django_site']) |
|
1096 qs.query.get_compiler(qs.db).as_sql() |
|
1097 # test passes if this doesn't raise an exception. |
|
1098 qs.query.get_compiler(qs.db).as_sql() |
|
1099 |
|
1100 def test_ticket9848(self): |
|
1101 # Make sure that updates which only filter on sub-tables don't |
|
1102 # inadvertently update the wrong records (bug #9848). |
|
1103 |
|
1104 # Make sure that the IDs from different tables don't happen to match. |
|
1105 self.assertQuerysetEqual( |
|
1106 Ranking.objects.filter(author__name='a1'), |
|
1107 ['<Ranking: 3: a1>'] |
|
1108 ) |
|
1109 self.assertEqual( |
|
1110 Ranking.objects.filter(author__name='a1').update(rank='4'), |
|
1111 1 |
|
1112 ) |
|
1113 r = Ranking.objects.filter(author__name='a1')[0] |
|
1114 self.assertNotEqual(r.id, r.author.id) |
|
1115 self.assertEqual(r.rank, 4) |
|
1116 r.rank = 3 |
|
1117 r.save() |
|
1118 self.assertQuerysetEqual( |
|
1119 Ranking.objects.all(), |
|
1120 ['<Ranking: 3: a1>', '<Ranking: 2: a2>', '<Ranking: 1: a3>'] |
|
1121 ) |
|
1122 |
|
1123 def test_ticket5261(self): |
|
1124 self.assertQuerysetEqual( |
|
1125 Note.objects.exclude(Q()), |
|
1126 ['<Note: n1>', '<Note: n2>'] |
|
1127 ) |
|
1128 |
|
1129 |
|
1130 class SelectRelatedTests(TestCase): |
|
1131 def test_tickets_3045_3288(self): |
|
1132 # Once upon a time, select_related() with circular relations would loop |
|
1133 # infinitely if you forgot to specify "depth". Now we set an arbitrary |
|
1134 # default upper bound. |
|
1135 self.assertQuerysetEqual(X.objects.all(), []) |
|
1136 self.assertQuerysetEqual(X.objects.select_related(), []) |
|
1137 |
|
1138 |
|
1139 class SubclassFKTests(TestCase): |
|
1140 def test_ticket7778(self): |
|
1141 # Model subclasses could not be deleted if a nullable foreign key |
|
1142 # relates to a model that relates back. |
|
1143 |
|
1144 num_celebs = Celebrity.objects.count() |
|
1145 tvc = TvChef.objects.create(name="Huey") |
|
1146 self.assertEqual(Celebrity.objects.count(), num_celebs + 1) |
|
1147 Fan.objects.create(fan_of=tvc) |
|
1148 Fan.objects.create(fan_of=tvc) |
|
1149 tvc.delete() |
|
1150 |
|
1151 # The parent object should have been deleted as well. |
|
1152 self.assertEqual(Celebrity.objects.count(), num_celebs) |
|
1153 |
|
1154 |
|
1155 class CustomPkTests(TestCase): |
|
1156 def test_ticket7371(self): |
|
1157 self.assertQuerysetEqual(Related.objects.order_by('custom'), []) |
|
1158 |
|
1159 |
|
1160 class NullableRelOrderingTests(TestCase): |
|
1161 def test_ticket10028(self): |
|
1162 # Ordering by model related to nullable relations(!) should use outer |
|
1163 # joins, so that all results are included. |
|
1164 _ = Plaything.objects.create(name="p1") |
|
1165 self.assertQuerysetEqual( |
|
1166 Plaything.objects.all(), |
|
1167 ['<Plaything: p1>'] |
|
1168 ) |
|
1169 |
|
1170 |
|
1171 class DisjunctiveFilterTests(TestCase): |
|
1172 def setUp(self): |
|
1173 self.n1 = Note.objects.create(note='n1', misc='foo', id=1) |
|
1174 ExtraInfo.objects.create(info='e1', note=self.n1) |
|
1175 |
|
1176 def test_ticket7872(self): |
|
1177 # Another variation on the disjunctive filtering theme. |
|
1178 |
|
1179 # For the purposes of this regression test, it's important that there is no |
|
1180 # Join object releated to the LeafA we create. |
|
1181 LeafA.objects.create(data='first') |
|
1182 self.assertQuerysetEqual(LeafA.objects.all(), ['<LeafA: first>']) |
|
1183 self.assertQuerysetEqual( |
|
1184 LeafA.objects.filter(Q(data='first')|Q(join__b__data='second')), |
|
1185 ['<LeafA: first>'] |
|
1186 ) |
|
1187 |
|
1188 def test_ticket8283(self): |
|
1189 # Checking that applying filters after a disjunction works correctly. |
|
1190 self.assertQuerysetEqual( |
|
1191 (ExtraInfo.objects.filter(note=self.n1)|ExtraInfo.objects.filter(info='e2')).filter(note=self.n1), |
|
1192 ['<ExtraInfo: e1>'] |
|
1193 ) |
|
1194 self.assertQuerysetEqual( |
|
1195 (ExtraInfo.objects.filter(info='e2')|ExtraInfo.objects.filter(note=self.n1)).filter(note=self.n1), |
|
1196 ['<ExtraInfo: e1>'] |
|
1197 ) |
|
1198 |
|
1199 |
|
1200 class Queries6Tests(TestCase): |
|
1201 def setUp(self): |
|
1202 generic = NamedCategory.objects.create(name="Generic") |
|
1203 t1 = Tag.objects.create(name='t1', category=generic) |
|
1204 t2 = Tag.objects.create(name='t2', parent=t1, category=generic) |
|
1205 t3 = Tag.objects.create(name='t3', parent=t1) |
|
1206 t4 = Tag.objects.create(name='t4', parent=t3) |
|
1207 t5 = Tag.objects.create(name='t5', parent=t3) |
|
1208 n1 = Note.objects.create(note='n1', misc='foo', id=1) |
|
1209 ann1 = Annotation.objects.create(name='a1', tag=t1) |
|
1210 ann1.notes.add(n1) |
|
1211 ann2 = Annotation.objects.create(name='a2', tag=t4) |
|
1212 |
|
1213 # FIXME!! This next test causes really weird PostgreSQL behaviour, but it's |
|
1214 # only apparent much later when the full test suite runs. I don't understand |
|
1215 # what's going on here yet. |
|
1216 ##def test_slicing_and_cache_interaction(self): |
|
1217 ## # We can do slicing beyond what is currently in the result cache, |
|
1218 ## # too. |
|
1219 ## |
|
1220 ## # We need to mess with the implementation internals a bit here to decrease the |
|
1221 ## # cache fill size so that we don't read all the results at once. |
|
1222 ## from django.db.models import query |
|
1223 ## query.ITER_CHUNK_SIZE = 2 |
|
1224 ## qs = Tag.objects.all() |
|
1225 ## |
|
1226 ## # Fill the cache with the first chunk. |
|
1227 ## self.assertTrue(bool(qs)) |
|
1228 ## self.assertEqual(len(qs._result_cache), 2) |
|
1229 ## |
|
1230 ## # Query beyond the end of the cache and check that it is filled out as required. |
|
1231 ## self.assertEqual(repr(qs[4]), '<Tag: t5>') |
|
1232 ## self.assertEqual(len(qs._result_cache), 5) |
|
1233 ## |
|
1234 ## # But querying beyond the end of the result set will fail. |
|
1235 ## self.assertRaises(IndexError, lambda: qs[100]) |
|
1236 |
|
1237 def test_parallel_iterators(self): |
|
1238 # Test that parallel iterators work. |
|
1239 qs = Tag.objects.all() |
|
1240 i1, i2 = iter(qs), iter(qs) |
|
1241 self.assertEqual(repr(i1.next()), '<Tag: t1>') |
|
1242 self.assertEqual(repr(i1.next()), '<Tag: t2>') |
|
1243 self.assertEqual(repr(i2.next()), '<Tag: t1>') |
|
1244 self.assertEqual(repr(i2.next()), '<Tag: t2>') |
|
1245 self.assertEqual(repr(i2.next()), '<Tag: t3>') |
|
1246 self.assertEqual(repr(i1.next()), '<Tag: t3>') |
|
1247 |
|
1248 qs = X.objects.all() |
|
1249 self.assertEqual(bool(qs), False) |
|
1250 self.assertEqual(bool(qs), False) |
|
1251 |
|
1252 def test_nested_queries_sql(self): |
|
1253 # Nested queries should not evaluate the inner query as part of constructing the |
|
1254 # SQL (so we should see a nested query here, indicated by two "SELECT" calls). |
|
1255 qs = Annotation.objects.filter(notes__in=Note.objects.filter(note="xyzzy")) |
|
1256 self.assertEqual( |
|
1257 qs.query.get_compiler(qs.db).as_sql()[0].count('SELECT'), |
|
1258 2 |
|
1259 ) |
|
1260 |
|
1261 def test_tickets_8921_9188(self): |
|
1262 # Incorrect SQL was being generated for certain types of exclude() |
|
1263 # queries that crossed multi-valued relations (#8921, #9188 and some |
|
1264 # pre-emptively discovered cases). |
|
1265 |
|
1266 self.assertQuerysetEqual( |
|
1267 PointerA.objects.filter(connection__pointerb__id=1), |
|
1268 [] |
|
1269 ) |
|
1270 self.assertQuerysetEqual( |
|
1271 PointerA.objects.exclude(connection__pointerb__id=1), |
|
1272 [] |
|
1273 ) |
|
1274 |
|
1275 self.assertQuerysetEqual( |
|
1276 Tag.objects.exclude(children=None), |
|
1277 ['<Tag: t1>', '<Tag: t3>'] |
|
1278 ) |
|
1279 |
|
1280 # This example is tricky because the parent could be NULL, so only checking |
|
1281 # parents with annotations omits some results (tag t1, in this case). |
|
1282 self.assertQuerysetEqual( |
|
1283 Tag.objects.exclude(parent__annotation__name="a1"), |
|
1284 ['<Tag: t1>', '<Tag: t4>', '<Tag: t5>'] |
|
1285 ) |
|
1286 |
|
1287 # The annotation->tag link is single values and tag->children links is |
|
1288 # multi-valued. So we have to split the exclude filter in the middle |
|
1289 # and then optimise the inner query without losing results. |
|
1290 self.assertQuerysetEqual( |
|
1291 Annotation.objects.exclude(tag__children__name="t2"), |
|
1292 ['<Annotation: a2>'] |
|
1293 ) |
|
1294 |
|
1295 # Nested queries are possible (although should be used with care, since |
|
1296 # they have performance problems on backends like MySQL. |
|
1297 |
|
1298 self.assertQuerysetEqual( |
|
1299 Annotation.objects.filter(notes__in=Note.objects.filter(note="n1")), |
|
1300 ['<Annotation: a1>'] |
|
1301 ) |
|
1302 |
|
1303 def test_ticket3739(self): |
|
1304 # The all() method on querysets returns a copy of the queryset. |
|
1305 q1 = Tag.objects.order_by('name') |
|
1306 self.assertTrue(q1 is not q1.all()) |
|
1307 |
|
1308 |
|
1309 class GeneratorExpressionTests(TestCase): |
|
1310 def test_ticket10432(self): |
|
1311 # Using an empty generator expression as the rvalue for an "__in" |
|
1312 # lookup is legal. |
|
1313 self.assertQuerysetEqual( |
|
1314 Note.objects.filter(pk__in=(x for x in ())), |
|
1315 [] |
|
1316 ) |
|
1317 |
|
1318 |
|
1319 class ComparisonTests(TestCase): |
|
1320 def setUp(self): |
|
1321 self.n1 = Note.objects.create(note='n1', misc='foo', id=1) |
|
1322 e1 = ExtraInfo.objects.create(info='e1', note=self.n1) |
|
1323 self.a2 = Author.objects.create(name='a2', num=2002, extra=e1) |
|
1324 |
|
1325 def test_ticket8597(self): |
|
1326 # Regression tests for case-insensitive comparisons |
|
1327 _ = Item.objects.create(name="a_b", created=datetime.datetime.now(), creator=self.a2, note=self.n1) |
|
1328 _ = Item.objects.create(name="x%y", created=datetime.datetime.now(), creator=self.a2, note=self.n1) |
|
1329 self.assertQuerysetEqual( |
|
1330 Item.objects.filter(name__iexact="A_b"), |
|
1331 ['<Item: a_b>'] |
|
1332 ) |
|
1333 self.assertQuerysetEqual( |
|
1334 Item.objects.filter(name__iexact="x%Y"), |
|
1335 ['<Item: x%y>'] |
|
1336 ) |
|
1337 self.assertQuerysetEqual( |
|
1338 Item.objects.filter(name__istartswith="A_b"), |
|
1339 ['<Item: a_b>'] |
|
1340 ) |
|
1341 self.assertQuerysetEqual( |
|
1342 Item.objects.filter(name__iendswith="A_b"), |
|
1343 ['<Item: a_b>'] |
|
1344 ) |
|
1345 |
|
1346 |
|
1347 class ExistsSql(TestCase): |
|
1348 def setUp(self): |
|
1349 settings.DEBUG = True |
|
1350 |
|
1351 def test_exists(self): |
|
1352 self.assertFalse(Tag.objects.exists()) |
|
1353 # Ok - so the exist query worked - but did it include too many columns? |
|
1354 self.assertTrue("id" not in connection.queries[-1]['sql'] and "name" not in connection.queries[-1]['sql']) |
|
1355 |
|
1356 def tearDown(self): |
|
1357 settings.DEBUG = False |
|
1358 |
|
1359 |
|
1360 class QuerysetOrderedTests(unittest.TestCase): |
|
1361 """ |
|
1362 Tests for the Queryset.ordered attribute. |
|
1363 """ |
|
1364 |
|
1365 def test_no_default_or_explicit_ordering(self): |
|
1366 self.assertEqual(Annotation.objects.all().ordered, False) |
|
1367 |
|
1368 def test_cleared_default_ordering(self): |
|
1369 self.assertEqual(Tag.objects.all().ordered, True) |
|
1370 self.assertEqual(Tag.objects.all().order_by().ordered, False) |
|
1371 |
|
1372 def test_explicit_ordering(self): |
|
1373 self.assertEqual(Annotation.objects.all().order_by('id').ordered, True) |
|
1374 |
|
1375 def test_order_by_extra(self): |
|
1376 self.assertEqual(Annotation.objects.all().extra(order_by=['id']).ordered, True) |
|
1377 |
|
1378 def test_annotated_ordering(self): |
|
1379 qs = Annotation.objects.annotate(num_notes=Count('notes')) |
|
1380 self.assertEqual(qs.ordered, False) |
|
1381 self.assertEqual(qs.order_by('num_notes').ordered, True) |
|
1382 |
|
1383 |
|
1384 class SubqueryTests(TestCase): |
|
1385 def setUp(self): |
|
1386 DumbCategory.objects.create(id=1) |
|
1387 DumbCategory.objects.create(id=2) |
|
1388 DumbCategory.objects.create(id=3) |
|
1389 |
|
1390 def test_ordered_subselect(self): |
|
1391 "Subselects honor any manual ordering" |
|
1392 try: |
|
1393 query = DumbCategory.objects.filter(id__in=DumbCategory.objects.order_by('-id')[0:2]) |
|
1394 self.assertEquals(set(query.values_list('id', flat=True)), set([2,3])) |
|
1395 |
|
1396 query = DumbCategory.objects.filter(id__in=DumbCategory.objects.order_by('-id')[:2]) |
|
1397 self.assertEquals(set(query.values_list('id', flat=True)), set([2,3])) |
|
1398 |
|
1399 query = DumbCategory.objects.filter(id__in=DumbCategory.objects.order_by('-id')[2:]) |
|
1400 self.assertEquals(set(query.values_list('id', flat=True)), set([1])) |
|
1401 except DatabaseError: |
|
1402 # Oracle and MySQL both have problems with sliced subselects. |
|
1403 # This prevents us from even evaluating this test case at all. |
|
1404 # Refs #10099 |
|
1405 self.assertFalse(connections[DEFAULT_DB_ALIAS].features.allow_sliced_subqueries) |
|
1406 |
|
1407 def test_sliced_delete(self): |
|
1408 "Delete queries can safely contain sliced subqueries" |
|
1409 try: |
|
1410 DumbCategory.objects.filter(id__in=DumbCategory.objects.order_by('-id')[0:1]).delete() |
|
1411 self.assertEquals(set(DumbCategory.objects.values_list('id', flat=True)), set([1,2])) |
|
1412 except DatabaseError: |
|
1413 # Oracle and MySQL both have problems with sliced subselects. |
|
1414 # This prevents us from even evaluating this test case at all. |
|
1415 # Refs #10099 |
|
1416 self.assertFalse(connections[DEFAULT_DB_ALIAS].features.allow_sliced_subqueries) |
|
1417 |
|
1418 |
|
1419 class CloneTests(TestCase): |
|
1420 def test_evaluated_queryset_as_argument(self): |
|
1421 "#13227 -- If a queryset is already evaluated, it can still be used as a query arg" |
|
1422 n = Note(note='Test1', misc='misc') |
|
1423 n.save() |
|
1424 e = ExtraInfo(info='good', note=n) |
|
1425 e.save() |
|
1426 |
|
1427 n_list = Note.objects.all() |
|
1428 # Evaluate the Note queryset, populating the query cache |
|
1429 list(n_list) |
|
1430 # Use the note queryset in a query, and evalute |
|
1431 # that query in a way that involves cloning. |
|
1432 try: |
|
1433 self.assertEquals(ExtraInfo.objects.filter(note__in=n_list)[0].info, 'good') |
|
1434 except: |
|
1435 self.fail('Query should be clonable') |
|
1436 |
|
1437 |
|
1438 class EmptyQuerySetTests(TestCase): |
|
1439 def test_emptyqueryset_values(self): |
|
1440 # #14366 -- Calling .values() on an EmptyQuerySet and then cloning that |
|
1441 # should not cause an error" |
|
1442 self.assertQuerysetEqual( |
|
1443 Number.objects.none().values('num').order_by('num'), [] |
|
1444 ) |
|
1445 |
|
1446 def test_values_subquery(self): |
|
1447 self.assertQuerysetEqual( |
|
1448 Number.objects.filter(pk__in=Number.objects.none().values("pk")), |
|
1449 [] |
|
1450 ) |
|
1451 self.assertQuerysetEqual( |
|
1452 Number.objects.filter(pk__in=Number.objects.none().values_list("pk")), |
|
1453 [] |
|
1454 ) |
|
1455 |
|
1456 |
|
1457 class ValuesQuerysetTests(BaseQuerysetTest): |
|
1458 def test_flat_values_lits(self): |
|
1459 Number.objects.create(num=72) |
|
1460 qs = Number.objects.values_list("num") |
|
1461 qs = qs.values_list("num", flat=True) |
|
1462 self.assertValueQuerysetEqual( |
|
1463 qs, [72] |
|
1464 ) |
|
1465 |
|
1466 |
|
1467 class WeirdQuerysetSlicingTests(BaseQuerysetTest): |
|
1468 def setUp(self): |
|
1469 Number.objects.create(num=1) |
|
1470 Number.objects.create(num=2) |
|
1471 |
|
1472 Article.objects.create(name='one', created=datetime.datetime.now()) |
|
1473 Article.objects.create(name='two', created=datetime.datetime.now()) |
|
1474 Article.objects.create(name='three', created=datetime.datetime.now()) |
|
1475 Article.objects.create(name='four', created=datetime.datetime.now()) |
|
1476 |
|
1477 def test_tickets_7698_10202(self): |
|
1478 # People like to slice with '0' as the high-water mark. |
|
1479 self.assertQuerysetEqual(Article.objects.all()[0:0], []) |
|
1480 self.assertQuerysetEqual(Article.objects.all()[0:0][:10], []) |
|
1481 self.assertEqual(Article.objects.all()[:0].count(), 0) |
|
1482 self.assertRaisesMessage( |
|
1483 AssertionError, |
|
1484 'Cannot change a query once a slice has been taken.', |
|
1485 Article.objects.all()[:0].latest, 'created' |
|
1486 ) |
|
1487 |
|
1488 |
|
1489 class EscapingTests(TestCase): |
|
1490 def test_ticket_7302(self): |
|
1491 # Reserved names are appropriately escaped |
|
1492 _ = ReservedName.objects.create(name='a', order=42) |
|
1493 ReservedName.objects.create(name='b', order=37) |
|
1494 self.assertQuerysetEqual( |
|
1495 ReservedName.objects.all().order_by('order'), |
|
1496 ['<ReservedName: b>', '<ReservedName: a>'] |
|
1497 ) |
|
1498 self.assertQuerysetEqual( |
|
1499 ReservedName.objects.extra(select={'stuff':'name'}, order_by=('order','stuff')), |
|
1500 ['<ReservedName: b>', '<ReservedName: a>'] |
|
1501 ) |
|
1502 |
|
1503 |
|
1504 # In Python 2.6 beta releases, exceptions raised in __len__ are swallowed |
|
1505 # (Python issue 1242657), so these cases return an empty list, rather than |
|
1506 # raising an exception. Not a lot we can do about that, unfortunately, due to |
|
1507 # the way Python handles list() calls internally. Thus, we skip the tests for |
|
1508 # Python 2.6. |
|
1509 if sys.version_info[:2] != (2, 6): |
|
1510 class OrderingLoopTests(BaseQuerysetTest): |
|
1511 def setUp(self): |
|
1512 generic = NamedCategory.objects.create(name="Generic") |
|
1513 t1 = Tag.objects.create(name='t1', category=generic) |
|
1514 t2 = Tag.objects.create(name='t2', parent=t1, category=generic) |
|
1515 t3 = Tag.objects.create(name='t3', parent=t1) |
|
1516 t4 = Tag.objects.create(name='t4', parent=t3) |
|
1517 t5 = Tag.objects.create(name='t5', parent=t3) |
|
1518 |
|
1519 def test_infinite_loop(self): |
|
1520 # If you're not careful, it's possible to introduce infinite loops via |
|
1521 # default ordering on foreign keys in a cycle. We detect that. |
|
1522 self.assertRaisesMessage( |
|
1523 FieldError, |
|
1524 'Infinite loop caused by ordering.', |
|
1525 lambda: list(LoopX.objects.all()) # Force queryset evaluation with list() |
|
1526 ) |
|
1527 self.assertRaisesMessage( |
|
1528 FieldError, |
|
1529 'Infinite loop caused by ordering.', |
|
1530 lambda: list(LoopZ.objects.all()) # Force queryset evaluation with list() |
|
1531 ) |
|
1532 |
|
1533 # Note that this doesn't cause an infinite loop, since the default |
|
1534 # ordering on the Tag model is empty (and thus defaults to using "id" |
|
1535 # for the related field). |
|
1536 self.assertEqual(len(Tag.objects.order_by('parent')), 5) |
|
1537 |
|
1538 # ... but you can still order in a non-recursive fashion amongst linked |
|
1539 # fields (the previous test failed because the default ordering was |
|
1540 # recursive). |
|
1541 self.assertQuerysetEqual( |
|
1542 LoopX.objects.all().order_by('y__x__y__x__id'), |
|
1543 [] |
|
1544 ) |
|
1545 |
|
1546 |
|
1547 # When grouping without specifying ordering, we add an explicit "ORDER BY NULL" |
|
1548 # portion in MySQL to prevent unnecessary sorting. |
|
1549 if settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] == "django.db.backends.mysql": |
|
1550 class GroupingTests(TestCase): |
|
1551 def test_null_ordering_added(self): |
|
1552 query = Tag.objects.values_list('parent_id', flat=True).order_by().query |
|
1553 query.group_by = ['parent_id'] |
|
1554 sql = query.get_compiler(DEFAULT_DB_ALIAS).as_sql()[0] |
|
1555 fragment = "ORDER BY " |
|
1556 pos = sql.find(fragment) |
|
1557 self.assertEqual(sql.find(fragment, pos + 1), -1) |
|
1558 self.assertEqual(sql.find("NULL", pos + len(fragment)), pos + len(fragment)) |
|
1559 |
|
1560 |
|
1561 # Sqlite 3 does not support passing in more than 1000 parameters except by |
|
1562 # changing a parameter at compilation time. |
|
1563 if settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] != "django.db.backends.sqlite3": |
|
1564 class InLookupTests(TestCase): |
|
1565 def test_ticket14244(self): |
|
1566 # Test that the "in" lookup works with lists of 1000 items or more. |
|
1567 Number.objects.all().delete() |
|
1568 numbers = range(2500) |
|
1569 for num in numbers: |
|
1570 _ = Number.objects.create(num=num) |
|
1571 self.assertEqual( |
|
1572 Number.objects.filter(num__in=numbers[:1000]).count(), |
|
1573 1000 |
|
1574 ) |
|
1575 self.assertEqual( |
|
1576 Number.objects.filter(num__in=numbers[:1001]).count(), |
|
1577 1001 |
|
1578 ) |
|
1579 self.assertEqual( |
|
1580 Number.objects.filter(num__in=numbers[:2000]).count(), |
|
1581 2000 |
|
1582 ) |
|
1583 self.assertEqual( |
|
1584 Number.objects.filter(num__in=numbers).count(), |
|
1585 2500 |
|
1586 ) |