Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

[1.2.X] Converted queries tests from doctests to unittests.

Thanks Russell and Alex for reviews and suggestions.

Backport of [14279] from trunk.

git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.2.X@14280 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 9bcdb620cbd7e2cda4b09b194b9ec7b3497c134e 1 parent da17c2b
Ramiro Morales authored October 19, 2010
1,093  tests/regressiontests/queries/models.py
@@ -2,15 +2,9 @@
2 2
 Various complex queries that have been problematic in the past.
3 3
 """
4 4
 
5  
-import datetime
6  
-import pickle
7  
-import sys
8 5
 import threading
9 6
 
10  
-from django.conf import settings
11  
-from django.db import models, DEFAULT_DB_ALIAS
12  
-from django.db.models import Count
13  
-from django.db.models.query import Q, ITER_CHUNK_SIZE, EmptyQuerySet
  7
+from django.db import models
14 8
 
15 9
 class DumbCategory(models.Model):
16 10
     pass
@@ -277,1085 +271,6 @@ class Meta:
277 271
     def __unicode__(self):
278 272
         return self.name
279 273
 
280  
-
281  
-__test__ = {'API_TESTS':"""
282  
->>> # Regression for #13156 -- exists() queries have minimal SQL
283  
->>> from django.db import connection
284  
->>> settings.DEBUG = True
285  
->>> Tag.objects.exists()
286  
-False
287  
->>> # Ok - so the exist query worked - but did it include too many columns?
288  
->>> "id" not in connection.queries[-1]['sql'] and "name" not in connection.queries[-1]['sql']
289  
-True
290  
->>> settings.DEBUG = False
291  
-
292  
->>> generic = NamedCategory.objects.create(name="Generic")
293  
->>> t1 = Tag.objects.create(name='t1', category=generic)
294  
->>> t2 = Tag.objects.create(name='t2', parent=t1, category=generic)
295  
->>> t3 = Tag.objects.create(name='t3', parent=t1)
296  
->>> t4 = Tag.objects.create(name='t4', parent=t3)
297  
->>> t5 = Tag.objects.create(name='t5', parent=t3)
298  
-
299  
->>> n1 = Note.objects.create(note='n1', misc='foo', id=1)
300  
->>> n2 = Note.objects.create(note='n2', misc='bar', id=2)
301  
->>> n3 = Note.objects.create(note='n3', misc='foo', id=3)
302  
-
303  
->>> ann1 = Annotation.objects.create(name='a1', tag=t1)
304  
->>> ann1.notes.add(n1)
305  
->>> ann2 = Annotation.objects.create(name='a2', tag=t4)
306  
->>> ann2.notes.add(n2, n3)
307  
-
308  
-Create these out of order so that sorting by 'id' will be different to sorting
309  
-by 'info'. Helps detect some problems later.
310  
->>> e2 = ExtraInfo.objects.create(info='e2', note=n2)
311  
->>> e1 = ExtraInfo.objects.create(info='e1', note=n1)
312  
-
313  
->>> a1 = Author.objects.create(name='a1', num=1001, extra=e1)
314  
->>> a2 = Author.objects.create(name='a2', num=2002, extra=e1)
315  
->>> a3 = Author.objects.create(name='a3', num=3003, extra=e2)
316  
->>> a4 = Author.objects.create(name='a4', num=4004, extra=e2)
317  
-
318  
->>> time1 = datetime.datetime(2007, 12, 19, 22, 25, 0)
319  
->>> time2 = datetime.datetime(2007, 12, 19, 21, 0, 0)
320  
->>> time3 = datetime.datetime(2007, 12, 20, 22, 25, 0)
321  
->>> time4 = datetime.datetime(2007, 12, 20, 21, 0, 0)
322  
->>> i1 = Item.objects.create(name='one', created=time1, modified=time1, creator=a1, note=n3)
323  
->>> i1.tags = [t1, t2]
324  
->>> i2 = Item.objects.create(name='two', created=time2, creator=a2, note=n2)
325  
->>> i2.tags = [t1, t3]
326  
->>> i3 = Item.objects.create(name='three', created=time3, creator=a2, note=n3)
327  
->>> i4 = Item.objects.create(name='four', created=time4, creator=a4, note=n3)
328  
->>> i4.tags = [t4]
329  
-
330  
->>> r1 = Report.objects.create(name='r1', creator=a1)
331  
->>> r2 = Report.objects.create(name='r2', creator=a3)
332  
->>> r3 = Report.objects.create(name='r3')
333  
-
334  
-Ordering by 'rank' gives us rank2, rank1, rank3. Ordering by the Meta.ordering
335  
-will be rank3, rank2, rank1.
336  
->>> rank1 = Ranking.objects.create(rank=2, author=a2)
337  
->>> rank2 = Ranking.objects.create(rank=1, author=a3)
338  
->>> rank3 = Ranking.objects.create(rank=3, author=a1)
339  
-
340  
->>> c1 = Cover.objects.create(title="first", item=i4)
341  
->>> c2 = Cover.objects.create(title="second", item=i2)
342  
-
343  
->>> num1 = Number.objects.create(num=4)
344  
->>> num2 = Number.objects.create(num=8)
345  
->>> num3 = Number.objects.create(num=12)
346  
-
347  
-Bug #1050
348  
->>> Item.objects.filter(tags__isnull=True)
349  
-[<Item: three>]
350  
->>> Item.objects.filter(tags__id__isnull=True)
351  
-[<Item: three>]
352  
-
353  
-Bug #1801
354  
->>> Author.objects.filter(item=i2)
355  
-[<Author: a2>]
356  
->>> Author.objects.filter(item=i3)
357  
-[<Author: a2>]
358  
->>> Author.objects.filter(item=i2) & Author.objects.filter(item=i3)
359  
-[<Author: a2>]
360  
-
361  
-Bug #2306
362  
-Checking that no join types are "left outer" joins.
363  
->>> query = Item.objects.filter(tags=t2).query
364  
->>> query.LOUTER not in [x[2] for x in query.alias_map.values()]
365  
-True
366  
-
367  
->>> Item.objects.filter(Q(tags=t1)).order_by('name')
368  
-[<Item: one>, <Item: two>]
369  
->>> Item.objects.filter(Q(tags=t1)).filter(Q(tags=t2))
370  
-[<Item: one>]
371  
->>> Item.objects.filter(Q(tags=t1)).filter(Q(creator__name='fred')|Q(tags=t2))
372  
-[<Item: one>]
373  
-
374  
-Each filter call is processed "at once" against a single table, so this is
375  
-different from the previous example as it tries to find tags that are two
376  
-things at once (rather than two tags).
377  
->>> Item.objects.filter(Q(tags=t1) & Q(tags=t2))
378  
-[]
379  
->>> Item.objects.filter(Q(tags=t1), Q(creator__name='fred')|Q(tags=t2))
380  
-[]
381  
-
382  
->>> qs = Author.objects.filter(ranking__rank=2, ranking__id=rank1.id)
383  
->>> list(qs)
384  
-[<Author: a2>]
385  
->>> qs.query.count_active_tables()
386  
-2
387  
->>> qs = Author.objects.filter(ranking__rank=2).filter(ranking__id=rank1.id)
388  
->>> qs.query.count_active_tables()
389  
-3
390  
-
391  
-Bug #4464
392  
->>> Item.objects.filter(tags=t1).filter(tags=t2)
393  
-[<Item: one>]
394  
->>> Item.objects.filter(tags__in=[t1, t2]).distinct().order_by('name')
395  
-[<Item: one>, <Item: two>]
396  
->>> Item.objects.filter(tags__in=[t1, t2]).filter(tags=t3)
397  
-[<Item: two>]
398  
-
399  
-Make sure .distinct() works with slicing (this was broken in Oracle).
400  
->>> Item.objects.filter(tags__in=[t1, t2]).order_by('name')[:3]
401  
-[<Item: one>, <Item: one>, <Item: two>]
402  
->>> Item.objects.filter(tags__in=[t1, t2]).distinct().order_by('name')[:3]
403  
-[<Item: one>, <Item: two>]
404  
-
405  
-Bug #2080, #3592
406  
->>> Author.objects.filter(item__name='one') | Author.objects.filter(name='a3')
407  
-[<Author: a1>, <Author: a3>]
408  
->>> Author.objects.filter(Q(item__name='one') | Q(name='a3'))
409  
-[<Author: a1>, <Author: a3>]
410  
->>> Author.objects.filter(Q(name='a3') | Q(item__name='one'))
411  
-[<Author: a1>, <Author: a3>]
412  
->>> Author.objects.filter(Q(item__name='three') | Q(report__name='r3'))
413  
-[<Author: a2>]
414  
-
415  
-Bug #4289
416  
-A slight variation on the above theme: restricting the choices by the lookup
417  
-constraints.
418  
->>> Number.objects.filter(num__lt=4)
419  
-[]
420  
->>> Number.objects.filter(num__gt=8, num__lt=12)
421  
-[]
422  
->>> Number.objects.filter(num__gt=8, num__lt=13)
423  
-[<Number: 12>]
424  
->>> Number.objects.filter(Q(num__lt=4) | Q(num__gt=8, num__lt=12))
425  
-[]
426  
->>> Number.objects.filter(Q(num__gt=8, num__lt=12) | Q(num__lt=4))
427  
-[]
428  
->>> Number.objects.filter(Q(num__gt=8) & Q(num__lt=12) | Q(num__lt=4))
429  
-[]
430  
->>> Number.objects.filter(Q(num__gt=7) & Q(num__lt=12) | Q(num__lt=4))
431  
-[<Number: 8>]
432  
-
433  
-Bug #12239
434  
-Float was being rounded to integer on gte queries on integer field.  Tests
435  
-show that gt, lt, gte, and lte work as desired.  Note that the fix changes
436  
-get_prep_lookup for gte and lt queries only.
437  
->>> Number.objects.filter(num__gt=11.9)
438  
-[<Number: 12>]
439  
->>> Number.objects.filter(num__gt=12)
440  
-[]
441  
->>> Number.objects.filter(num__gt=12.0)
442  
-[]
443  
->>> Number.objects.filter(num__gt=12.1)
444  
-[]
445  
->>> Number.objects.filter(num__lt=12)
446  
-[<Number: 4>, <Number: 8>]
447  
->>> Number.objects.filter(num__lt=12.0)
448  
-[<Number: 4>, <Number: 8>]
449  
->>> Number.objects.filter(num__lt=12.1)
450  
-[<Number: 4>, <Number: 8>, <Number: 12>]
451  
->>> Number.objects.filter(num__gte=11.9)
452  
-[<Number: 12>]
453  
->>> Number.objects.filter(num__gte=12)
454  
-[<Number: 12>]
455  
->>> Number.objects.filter(num__gte=12.0)
456  
-[<Number: 12>]
457  
->>> Number.objects.filter(num__gte=12.1)
458  
-[]
459  
->>> Number.objects.filter(num__gte=12.9)
460  
-[]
461  
->>> Number.objects.filter(num__lte=11.9)
462  
-[<Number: 4>, <Number: 8>]
463  
->>> Number.objects.filter(num__lte=12)
464  
-[<Number: 4>, <Number: 8>, <Number: 12>]
465  
->>> Number.objects.filter(num__lte=12.0)
466  
-[<Number: 4>, <Number: 8>, <Number: 12>]
467  
->>> Number.objects.filter(num__lte=12.1)
468  
-[<Number: 4>, <Number: 8>, <Number: 12>]
469  
->>> Number.objects.filter(num__lte=12.9)
470  
-[<Number: 4>, <Number: 8>, <Number: 12>]
471  
-
472  
-Bug #7872
473  
-Another variation on the disjunctive filtering theme.
474  
-
475  
-# For the purposes of this regression test, it's important that there is no
476  
-# Join object releated to the LeafA we create.
477  
->>> LeafA.objects.create(data='first')
478  
-<LeafA: first>
479  
->>> LeafA.objects.filter(Q(data='first')|Q(join__b__data='second'))
480  
-[<LeafA: first>]
481  
-
482  
-Bug #6074
483  
-Merging two empty result sets shouldn't leave a queryset with no constraints
484  
-(which would match everything).
485  
->>> Author.objects.filter(Q(id__in=[]))
486  
-[]
487  
->>> Author.objects.filter(Q(id__in=[])|Q(id__in=[]))
488  
-[]
489  
-
490  
-Bug #1878, #2939
491  
->>> Item.objects.values('creator').distinct().count()
492  
-3
493  
-
494  
-# Create something with a duplicate 'name' so that we can test multi-column
495  
-# cases (which require some tricky SQL transformations under the covers).
496  
->>> xx = Item(name='four', created=time1, creator=a2, note=n1)
497  
->>> xx.save()
498  
->>> Item.objects.exclude(name='two').values('creator', 'name').distinct().count()
499  
-4
500  
->>> Item.objects.exclude(name='two').extra(select={'foo': '%s'}, select_params=(1,)).values('creator', 'name', 'foo').distinct().count()
501  
-4
502  
->>> Item.objects.exclude(name='two').extra(select={'foo': '%s'}, select_params=(1,)).values('creator', 'name').distinct().count()
503  
-4
504  
->>> xx.delete()
505  
-
506  
-Bug #7323
507  
->>> Item.objects.values('creator', 'name').count()
508  
-4
509  
-
510  
-Bug #2253
511  
->>> q1 = Item.objects.order_by('name')
512  
->>> q2 = Item.objects.filter(id=i1.id)
513  
->>> q1
514  
-[<Item: four>, <Item: one>, <Item: three>, <Item: two>]
515  
->>> q2
516  
-[<Item: one>]
517  
->>> (q1 | q2).order_by('name')
518  
-[<Item: four>, <Item: one>, <Item: three>, <Item: two>]
519  
->>> (q1 & q2).order_by('name')
520  
-[<Item: one>]
521  
-
522  
-# FIXME: This is difficult to fix and very much an edge case, so punt for now.
523  
-# # This is related to the order_by() tests, below, but the old bug exhibited
524  
-# # itself here (q2 was pulling too many tables into the combined query with the
525  
-# # new ordering, but only because we have evaluated q2 already).
526  
-# >>> len((q1 & q2).order_by('name').query.tables)
527  
-# 1
528  
-
529  
->>> q1 = Item.objects.filter(tags=t1)
530  
->>> q2 = Item.objects.filter(note=n3, tags=t2)
531  
->>> q3 = Item.objects.filter(creator=a4)
532  
->>> ((q1 & q2) | q3).order_by('name')
533  
-[<Item: four>, <Item: one>]
534  
-
535  
-Bugs #4088, #4306
536  
->>> Report.objects.filter(creator=1001)
537  
-[<Report: r1>]
538  
->>> Report.objects.filter(creator__num=1001)
539  
-[<Report: r1>]
540  
->>> Report.objects.filter(creator__id=1001)
541  
-[]
542  
->>> Report.objects.filter(creator__id=a1.id)
543  
-[<Report: r1>]
544  
->>> Report.objects.filter(creator__name='a1')
545  
-[<Report: r1>]
546  
-
547  
-Bug #4510
548  
->>> Author.objects.filter(report__name='r1')
549  
-[<Author: a1>]
550  
-
551  
-Bug #7378
552  
->>> a1.report_set.all()
553  
-[<Report: r1>]
554  
-
555  
-Bug #5324, #6704
556  
->>> Item.objects.filter(tags__name='t4')
557  
-[<Item: four>]
558  
->>> Item.objects.exclude(tags__name='t4').order_by('name').distinct()
559  
-[<Item: one>, <Item: three>, <Item: two>]
560  
->>> Item.objects.exclude(tags__name='t4').order_by('name').distinct().reverse()
561  
-[<Item: two>, <Item: three>, <Item: one>]
562  
->>> Author.objects.exclude(item__name='one').distinct().order_by('name')
563  
-[<Author: a2>, <Author: a3>, <Author: a4>]
564  
-
565  
-
566  
-# Excluding across a m2m relation when there is more than one related object
567  
-# associated was problematic.
568  
->>> Item.objects.exclude(tags__name='t1').order_by('name')
569  
-[<Item: four>, <Item: three>]
570  
->>> Item.objects.exclude(tags__name='t1').exclude(tags__name='t4')
571  
-[<Item: three>]
572  
-
573  
-# Excluding from a relation that cannot be NULL should not use outer joins.
574  
->>> query = Item.objects.exclude(creator__in=[a1, a2]).query
575  
->>> query.LOUTER not in [x[2] for x in query.alias_map.values()]
576  
-True
577  
-
578  
-Similarly, when one of the joins cannot possibly, ever, involve NULL values (Author -> ExtraInfo, in the following), it should never be promoted to a left outer join. So the following query should only involve one "left outer" join (Author -> Item is 0-to-many).
579  
->>> qs = Author.objects.filter(id=a1.id).filter(Q(extra__note=n1)|Q(item__note=n3))
580  
->>> len([x[2] for x in qs.query.alias_map.values() if x[2] == query.LOUTER and qs.query.alias_refcount[x[1]]])
581  
-1
582  
-
583  
-The previous changes shouldn't affect nullable foreign key joins.
584  
->>> Tag.objects.filter(parent__isnull=True).order_by('name')
585  
-[<Tag: t1>]
586  
->>> Tag.objects.exclude(parent__isnull=True).order_by('name')
587  
-[<Tag: t2>, <Tag: t3>, <Tag: t4>, <Tag: t5>]
588  
->>> Tag.objects.exclude(Q(parent__name='t1') | Q(parent__isnull=True)).order_by('name')
589  
-[<Tag: t4>, <Tag: t5>]
590  
->>> Tag.objects.exclude(Q(parent__isnull=True) | Q(parent__name='t1')).order_by('name')
591  
-[<Tag: t4>, <Tag: t5>]
592  
->>> Tag.objects.exclude(Q(parent__parent__isnull=True)).order_by('name')
593  
-[<Tag: t4>, <Tag: t5>]
594  
->>> Tag.objects.filter(~Q(parent__parent__isnull=True)).order_by('name')
595  
-[<Tag: t4>, <Tag: t5>]
596  
-
597  
-Bug #2091
598  
->>> t = Tag.objects.get(name='t4')
599  
->>> Item.objects.filter(tags__in=[t])
600  
-[<Item: four>]
601  
-
602  
-Combining querysets built on different models should behave in a well-defined
603  
-fashion. We raise an error.
604  
->>> Author.objects.all() & Tag.objects.all()
605  
-Traceback (most recent call last):
606  
-...
607  
-AssertionError: Cannot combine queries on two different base models.
608  
->>> Author.objects.all() | Tag.objects.all()
609  
-Traceback (most recent call last):
610  
-...
611  
-AssertionError: Cannot combine queries on two different base models.
612  
-
613  
-Bug #3141
614  
->>> Author.objects.extra(select={'foo': '1'}).count()
615  
-4
616  
->>> Author.objects.extra(select={'foo': '%s'}, select_params=(1,)).count()
617  
-4
618  
-
619  
-Bug #2400
620  
->>> Author.objects.filter(item__isnull=True)
621  
-[<Author: a3>]
622  
->>> Tag.objects.filter(item__isnull=True)
623  
-[<Tag: t5>]
624  
-
625  
-Bug #2496
626  
->>> Item.objects.extra(tables=['queries_author']).select_related().order_by('name')[:1]
627  
-[<Item: four>]
628  
-
629  
-Bug #2076
630  
-# Ordering on related tables should be possible, even if the table is not
631  
-# otherwise involved.
632  
->>> Item.objects.order_by('note__note', 'name')
633  
-[<Item: two>, <Item: four>, <Item: one>, <Item: three>]
634  
-
635  
-# Ordering on a related field should use the remote model's default ordering as
636  
-# a final step.
637  
->>> Author.objects.order_by('extra', '-name')
638  
-[<Author: a2>, <Author: a1>, <Author: a4>, <Author: a3>]
639  
-
640  
-# Using remote model default ordering can span multiple models (in this case,
641  
-# Cover is ordered by Item's default, which uses Note's default).
642  
->>> Cover.objects.all()
643  
-[<Cover: first>, <Cover: second>]
644  
-
645  
-# If the remote model does not have a default ordering, we order by its 'id'
646  
-# field.
647  
->>> Item.objects.order_by('creator', 'name')
648  
-[<Item: one>, <Item: three>, <Item: two>, <Item: four>]
649  
-
650  
-# Cross model ordering is possible in Meta, too.
651  
->>> Ranking.objects.all()
652  
-[<Ranking: 3: a1>, <Ranking: 2: a2>, <Ranking: 1: a3>]
653  
->>> Ranking.objects.all().order_by('rank')
654  
-[<Ranking: 1: a3>, <Ranking: 2: a2>, <Ranking: 3: a1>]
655  
-
656  
-# Ordering by a many-valued attribute (e.g. a many-to-many or reverse
657  
-# ForeignKey) is legal, but the results might not make sense. That isn't
658  
-# Django's problem. Garbage in, garbage out.
659  
->>> Item.objects.filter(tags__isnull=False).order_by('tags', 'id')
660  
-[<Item: one>, <Item: two>, <Item: one>, <Item: two>, <Item: four>]
661  
-
662  
-# If we replace the default ordering, Django adjusts the required tables
663  
-# automatically. Item normally requires a join with Note to do the default
664  
-# ordering, but that isn't needed here.
665  
->>> qs = Item.objects.order_by('name')
666  
->>> list(qs)
667  
-[<Item: four>, <Item: one>, <Item: three>, <Item: two>]
668  
->>> len(qs.query.tables)
669  
-1
670  
-
671  
-# Ordering of extra() pieces is possible, too and you can mix extra fields and
672  
-# model fields in the ordering.
673  
->>> Ranking.objects.extra(tables=['django_site'], order_by=['-django_site.id', 'rank'])
674  
-[<Ranking: 1: a3>, <Ranking: 2: a2>, <Ranking: 3: a1>]
675  
-
676  
->>> qs = Ranking.objects.extra(select={'good': 'case when rank > 2 then 1 else 0 end'})
677  
->>> [o.good for o in qs.extra(order_by=('-good',))] == [True, False, False]
678  
-True
679  
->>> qs.extra(order_by=('-good', 'id'))
680  
-[<Ranking: 3: a1>, <Ranking: 2: a2>, <Ranking: 1: a3>]
681  
-
682  
-# Despite having some extra aliases in the query, we can still omit them in a
683  
-# values() query.
684  
->>> dicts = qs.values('id', 'rank').order_by('id')
685  
->>> [sorted(d.items()) for d in dicts]
686  
-[[('id', 1), ('rank', 2)], [('id', 2), ('rank', 1)], [('id', 3), ('rank', 3)]]
687  
-
688  
-Bug #7256
689  
-# An empty values() call includes all aliases, including those from an extra()
690  
->>> dicts = qs.values().order_by('id')
691  
->>> [sorted(d.items()) for d in dicts]
692  
-[[('author_id', 2), ('good', 0), ('id', 1), ('rank', 2)], [('author_id', 3), ('good', 0), ('id', 2), ('rank', 1)], [('author_id', 1), ('good', 1), ('id', 3), ('rank', 3)]]
693  
-
694  
-Bugs #2874, #3002
695  
->>> qs = Item.objects.select_related().order_by('note__note', 'name')
696  
->>> list(qs)
697  
-[<Item: two>, <Item: four>, <Item: one>, <Item: three>]
698  
-
699  
-# This is also a good select_related() test because there are multiple Note
700  
-# entries in the SQL. The two Note items should be different.
701  
->>> qs[0].note, qs[0].creator.extra.note
702  
-(<Note: n2>, <Note: n1>)
703  
-
704  
-Bug #3037
705  
->>> Item.objects.filter(Q(creator__name='a3', name='two')|Q(creator__name='a4', name='four'))
706  
-[<Item: four>]
707  
-
708  
-Bug #5321, #7070
709  
-
710  
-Ordering columns must be included in the output columns. Note that this means
711  
-results that might otherwise be distinct are not (if there are multiple values
712  
-in the ordering cols), as in this example. This isn't a bug; it's a warning to
713  
-be careful with the selection of ordering columns.
714  
-
715  
->>> Note.objects.values('misc').distinct().order_by('note', '-misc')
716  
-[{'misc': u'foo'}, {'misc': u'bar'}, {'misc': u'foo'}]
717  
-
718  
-Bug #4358
719  
-If you don't pass any fields to values(), relation fields are returned as
720  
-"foo_id" keys, not "foo". For consistency, you should be able to pass "foo_id"
721  
-in the fields list and have it work, too. We actually allow both "foo" and
722  
-"foo_id".
723  
-
724  
-# The *_id version is returned by default.
725  
->>> 'note_id' in ExtraInfo.objects.values()[0]
726  
-True
727  
-
728  
-# You can also pass it in explicitly.
729  
->>> ExtraInfo.objects.values('note_id')
730  
-[{'note_id': 1}, {'note_id': 2}]
731  
-
732  
-# ...or use the field name.
733  
->>> ExtraInfo.objects.values('note')
734  
-[{'note': 1}, {'note': 2}]
735  
-
736  
-Bug #5261
737  
->>> Note.objects.exclude(Q())
738  
-[<Note: n1>, <Note: n2>, <Note: n3>]
739  
-
740  
-Bug #3045, #3288
741  
-Once upon a time, select_related() with circular relations would loop
742  
-infinitely if you forgot to specify "depth". Now we set an arbitrary default
743  
-upper bound.
744  
->>> X.objects.all()
745  
-[]
746  
->>> X.objects.select_related()
747  
-[]
748  
-
749  
-Bug #3739
750  
-The all() method on querysets returns a copy of the queryset.
751  
->>> q1 = Item.objects.order_by('name')
752  
->>> id(q1) == id(q1.all())
753  
-False
754  
-
755  
-Bug #2902
756  
-Parameters can be given to extra_select, *if* you use a SortedDict.
757  
-
758  
-(First we need to know which order the keys fall in "naturally" on your system,
759  
-so we can put things in the wrong way around from normal. A normal dict would
760  
-thus fail.)
761  
->>> from django.utils.datastructures import SortedDict
762  
->>> s = [('a', '%s'), ('b', '%s')]
763  
->>> params = ['one', 'two']
764  
->>> if {'a': 1, 'b': 2}.keys() == ['a', 'b']:
765  
-...     s.reverse()
766  
-...     params.reverse()
767  
-
768  
-# This slightly odd comparison works around the fact that PostgreSQL will
769  
-# return 'one' and 'two' as strings, not Unicode objects. It's a side-effect of
770  
-# using constants here and not a real concern.
771  
->>> d = Item.objects.extra(select=SortedDict(s), select_params=params).values('a', 'b')[0]
772  
->>> d == {'a': u'one', 'b': u'two'}
773  
-True
774  
-
775  
-# Order by the number of tags attached to an item.
776  
->>> l = Item.objects.extra(select={'count': 'select count(*) from queries_item_tags where queries_item_tags.item_id = queries_item.id'}).order_by('-count')
777  
->>> [o.count for o in l]
778  
-[2, 2, 1, 0]
779  
-
780  
-Bug #6154
781  
-Multiple filter statements are joined using "AND" all the time.
782  
-
783  
->>> Author.objects.filter(id=a1.id).filter(Q(extra__note=n1)|Q(item__note=n3))
784  
-[<Author: a1>]
785  
->>> Author.objects.filter(Q(extra__note=n1)|Q(item__note=n3)).filter(id=a1.id)
786  
-[<Author: a1>]
787  
-
788  
-Bug #6981
789  
->>> Tag.objects.select_related('parent').order_by('name')
790  
-[<Tag: t1>, <Tag: t2>, <Tag: t3>, <Tag: t4>, <Tag: t5>]
791  
-
792  
-Bug #9926
793  
->>> Tag.objects.select_related("parent", "category").order_by('name')
794  
-[<Tag: t1>, <Tag: t2>, <Tag: t3>, <Tag: t4>, <Tag: t5>]
795  
->>> Tag.objects.select_related('parent', "parent__category").order_by('name')
796  
-[<Tag: t1>, <Tag: t2>, <Tag: t3>, <Tag: t4>, <Tag: t5>]
797  
-
798  
-Bug #6180, #6203 -- dates with limits and/or counts
799  
->>> Item.objects.count()
800  
-4
801  
->>> Item.objects.dates('created', 'month').count()
802  
-1
803  
->>> Item.objects.dates('created', 'day').count()
804  
-2
805  
->>> len(Item.objects.dates('created', 'day'))
806  
-2
807  
->>> Item.objects.dates('created', 'day')[0]
808  
-datetime.datetime(2007, 12, 19, 0, 0)
809  
-
810  
-Bug #7087/#12242 -- dates with extra select columns
811  
->>> Item.objects.dates('created', 'day').extra(select={'a': 1})
812  
-[datetime.datetime(2007, 12, 19, 0, 0), datetime.datetime(2007, 12, 20, 0, 0)]
813  
-
814  
->>> Item.objects.extra(select={'a': 1}).dates('created', 'day')
815  
-[datetime.datetime(2007, 12, 19, 0, 0), datetime.datetime(2007, 12, 20, 0, 0)]
816  
-
817  
->>> name="one"
818  
->>> Item.objects.dates('created', 'day').extra(where=['name=%s'], params=[name])
819  
-[datetime.datetime(2007, 12, 19, 0, 0)]
820  
-
821  
->>> Item.objects.extra(where=['name=%s'], params=[name]).dates('created', 'day')
822  
-[datetime.datetime(2007, 12, 19, 0, 0)]
823  
-
824  
-Bug #7155 -- nullable dates
825  
->>> Item.objects.dates('modified', 'day')
826  
-[datetime.datetime(2007, 12, 19, 0, 0)]
827  
-
828  
-Test that parallel iterators work.
829  
-
830  
->>> qs = Tag.objects.all()
831  
->>> i1, i2 = iter(qs), iter(qs)
832  
->>> i1.next(), i1.next()
833  
-(<Tag: t1>, <Tag: t2>)
834  
->>> i2.next(), i2.next(), i2.next()
835  
-(<Tag: t1>, <Tag: t2>, <Tag: t3>)
836  
->>> i1.next()
837  
-<Tag: t3>
838  
-
839  
->>> qs = X.objects.all()
840  
->>> bool(qs)
841  
-False
842  
->>> bool(qs)
843  
-False
844  
-
845  
-We can do slicing beyond what is currently in the result cache, too.
846  
-
847  
-## FIXME!! This next test causes really weird PostgreSQL behaviour, but it's
848  
-## only apparent much later when the full test suite runs. I don't understand
849  
-## what's going on here yet.
850  
-##
851  
-## # We need to mess with the implementation internals a bit here to decrease the
852  
-## # cache fill size so that we don't read all the results at once.
853  
-## >>> from django.db.models import query
854  
-## >>> query.ITER_CHUNK_SIZE = 2
855  
-## >>> qs = Tag.objects.all()
856  
-##
857  
-## # Fill the cache with the first chunk.
858  
-## >>> bool(qs)
859  
-## True
860  
-## >>> len(qs._result_cache)
861  
-## 2
862  
-##
863  
-## # Query beyond the end of the cache and check that it is filled out as required.
864  
-## >>> qs[4]
865  
-## <Tag: t5>
866  
-## >>> len(qs._result_cache)
867  
-## 5
868  
-##
869  
-## # But querying beyond the end of the result set will fail.
870  
-## >>> qs[100]
871  
-## Traceback (most recent call last):
872  
-## ...
873  
-## IndexError: ...
874  
-
875  
-Bug #7045 -- extra tables used to crash SQL construction on the second use.
876  
->>> qs = Ranking.objects.extra(tables=['django_site'])
877  
->>> s = qs.query.get_compiler(qs.db).as_sql()
878  
->>> s = qs.query.get_compiler(qs.db).as_sql()   # test passes if this doesn't raise an exception.
879  
-
880  
-Bug #7098 -- Make sure semi-deprecated ordering by related models syntax still
881  
-works.
882  
->>> Item.objects.values('note__note').order_by('queries_note.note', 'id')
883  
-[{'note__note': u'n2'}, {'note__note': u'n3'}, {'note__note': u'n3'}, {'note__note': u'n3'}]
884  
-
885  
-Bug #7096 -- Make sure exclude() with multiple conditions continues to work.
886  
->>> Tag.objects.filter(parent=t1, name='t3').order_by('name')
887  
-[<Tag: t3>]
888  
->>> Tag.objects.exclude(parent=t1, name='t3').order_by('name')
889  
-[<Tag: t1>, <Tag: t2>, <Tag: t4>, <Tag: t5>]
890  
->>> Item.objects.exclude(tags__name='t1', name='one').order_by('name').distinct()
891  
-[<Item: four>, <Item: three>, <Item: two>]
892  
->>> Item.objects.filter(name__in=['three', 'four']).exclude(tags__name='t1').order_by('name')
893  
-[<Item: four>, <Item: three>]
894  
-
895  
-More twisted cases, involving nested negations.
896  
->>> Item.objects.exclude(~Q(tags__name='t1', name='one'))
897  
-[<Item: one>]
898  
->>> Item.objects.filter(~Q(tags__name='t1', name='one'), name='two')
899  
-[<Item: two>]
900  
->>> Item.objects.exclude(~Q(tags__name='t1', name='one'), name='two')
901  
-[<Item: four>, <Item: one>, <Item: three>]
902  
-
903  
-Bug #7095
904  
-Updates that are filtered on the model being updated are somewhat tricky
905  
-in MySQL. This exercises that case.
906  
->>> mm = ManagedModel.objects.create(data='mm1', tag=t1, public=True)
907  
->>> ManagedModel.objects.update(data='mm')
908  
-1
909  
-
910  
-A values() or values_list() query across joined models must use outer joins
911  
-appropriately.
912  
->>> Report.objects.values_list("creator__extra__info", flat=True).order_by("name")
913  
-[u'e1', u'e2', <NONE_OR_EMPTY_UNICODE>]
914  
-
915  
-Similarly for select_related(), joins beyond an initial nullable join must
916  
-use outer joins so that all results are included.
917  
->>> Report.objects.select_related("creator", "creator__extra").order_by("name")
918  
-[<Report: r1>, <Report: r2>, <Report: r3>]
919  
-
920  
-When there are multiple paths to a table from another table, we have to be
921  
-careful not to accidentally reuse an inappropriate join when using
922  
-select_related(). We used to return the parent's Detail record here by mistake.
923  
-
924  
->>> d1 = Detail.objects.create(data="d1")
925  
->>> d2 = Detail.objects.create(data="d2")
926  
->>> m1 = Member.objects.create(name="m1", details=d1)
927  
->>> m2 = Member.objects.create(name="m2", details=d2)
928  
->>> c1 = Child.objects.create(person=m2, parent=m1)
929  
->>> obj = m1.children.select_related("person__details")[0]
930  
->>> obj.person.details.data
931  
-u'd2'
932  
-
933  
-Bug #7076 -- excluding shouldn't eliminate NULL entries.
934  
->>> Item.objects.exclude(modified=time1).order_by('name')
935  
-[<Item: four>, <Item: three>, <Item: two>]
936  
->>> Tag.objects.exclude(parent__name=t1.name)
937  
-[<Tag: t1>, <Tag: t4>, <Tag: t5>]
938  
-
939  
-Bug #7181 -- ordering by related tables should accomodate nullable fields (this
940  
-test is a little tricky, since NULL ordering is database dependent. Instead, we
941  
-just count the number of results).
942  
->>> len(Tag.objects.order_by('parent__name'))
943  
-5
944  
-
945  
-Bug #7107 -- this shouldn't create an infinite loop.
946  
->>> Valid.objects.all()
947  
-[]
948  
-
949  
-Empty querysets can be merged with others.
950  
->>> Note.objects.none() | Note.objects.all()
951  
-[<Note: n1>, <Note: n2>, <Note: n3>]
952  
->>> Note.objects.all() | Note.objects.none()
953  
-[<Note: n1>, <Note: n2>, <Note: n3>]
954  
->>> Note.objects.none() & Note.objects.all()
955  
-[]
956  
->>> Note.objects.all() & Note.objects.none()
957  
-[]
958  
-
959  
-Bug #7204, #7506 -- make sure querysets with related fields can be pickled. If
960  
-this doesn't crash, it's a Good Thing.
961  
->>> out = pickle.dumps(Item.objects.all())
962  
-
963  
-We should also be able to pickle things that use select_related(). The only
964  
-tricky thing here is to ensure that we do the related selections properly after
965  
-unpickling.
966  
->>> qs = Item.objects.select_related()
967  
->>> query = qs.query.get_compiler(qs.db).as_sql()[0]
968  
->>> query2 = pickle.loads(pickle.dumps(qs.query))
969  
->>> query2.get_compiler(qs.db).as_sql()[0] == query
970  
-True
971  
-
972  
-Check pickling of deferred-loading querysets
973  
->>> qs = Item.objects.defer('name', 'creator')
974  
->>> q2 = pickle.loads(pickle.dumps(qs))
975  
->>> list(qs) == list(q2)
976  
-True
977  
->>> q3 = pickle.loads(pickle.dumps(qs, pickle.HIGHEST_PROTOCOL))
978  
->>> list(qs) == list(q3)
979  
-True
980  
-
981  
-Bug #7277
982  
->>> n1.annotation_set.filter(Q(tag=t5) | Q(tag__children=t5) | Q(tag__children__children=t5))
983  
-[<Annotation: a1>]
984  
-
985  
-Bug #7371
986  
->>> Related.objects.order_by('custom')
987  
-[]
988  
-
989  
-Bug #7448, #7707 -- Complex objects should be converted to strings before being
990  
-used in lookups.
991  
->>> Item.objects.filter(created__in=[time1, time2])
992  
-[<Item: one>, <Item: two>]
993  
-
994  
-Bug #7698, #10202 -- People like to slice with '0' as the high-water mark.
995  
->>> Item.objects.all()[0:0]
996  
-[]
997  
->>> Item.objects.all()[0:0][:10]
998  
-[]
999  
->>> Item.objects.all()[:0].count()
1000  
-0
1001  
->>> Item.objects.all()[:0].latest('created')
1002  
-Traceback (most recent call last):
1003  
-    ...
1004  
-AssertionError: Cannot change a query once a slice has been taken.
1005  
-
1006  
-Bug #7411 - saving to db must work even with partially read result set in
1007  
-another cursor.
1008  
-
1009  
->>> for num in range(2 * ITER_CHUNK_SIZE + 1):
1010  
-...     _ = Number.objects.create(num=num)
1011  
-
1012  
->>> for i, obj in enumerate(Number.objects.all()):
1013  
-...     obj.save()
1014  
-...     if i > 10: break
1015  
-
1016  
-Bug #7759 -- count should work with a partially read result set.
1017  
->>> count = Number.objects.count()
1018  
->>> qs = Number.objects.all()
1019  
->>> for obj in qs:
1020  
-...     qs.count() == count
1021  
-...     break
1022  
-True
1023  
-
1024  
-Bug #7235 -- an EmptyQuerySet should not raise exceptions if it is filtered.
1025  
->>> q = EmptyQuerySet()
1026  
->>> q.all()
1027  
-[]
1028  
->>> q.filter(x=10)
1029  
-[]
1030  
->>> q.exclude(y=3)
1031  
-[]
1032  
->>> q.complex_filter({'pk': 1})
1033  
-[]
1034  
->>> q.select_related('spam', 'eggs')
1035  
-[]
1036  
->>> q.annotate(Count('eggs'))
1037  
-[]
1038  
->>> q.order_by('-pub_date', 'headline')
1039  
-[]
1040  
->>> q.distinct()
1041  
-[]
1042  
->>> q.extra(select={'is_recent': "pub_date > '2006-01-01'"})
1043  
-[]
1044  
->>> q.query.low_mark = 1
1045  
->>> q.extra(select={'is_recent': "pub_date > '2006-01-01'"})
1046  
-Traceback (most recent call last):
1047  
-...
1048  
-AssertionError: Cannot change a query once a slice has been taken
1049  
->>> q.reverse()
1050  
-[]
1051  
->>> q.defer('spam', 'eggs')
1052  
-[]
1053  
->>> q.only('spam', 'eggs')
1054  
-[]
1055  
-
1056  
-Bug #7791 -- there were "issues" when ordering and distinct-ing on fields
1057  
-related via ForeignKeys.
1058  
->>> len(Note.objects.order_by('extrainfo__info').distinct())
1059  
-3
1060  
-
1061  
-Bug #7778 - Model subclasses could not be deleted if a nullable foreign key
1062  
-relates to a model that relates back.
1063  
-
1064  
->>> num_celebs = Celebrity.objects.count()
1065  
->>> tvc = TvChef.objects.create(name="Huey")
1066  
->>> Celebrity.objects.count() == num_celebs + 1
1067  
-True
1068  
->>> f1 = Fan.objects.create(fan_of=tvc)
1069  
->>> f2 = Fan.objects.create(fan_of=tvc)
1070  
->>> tvc.delete()
1071  
-
1072  
-# The parent object should have been deleted as well.
1073  
->>> Celebrity.objects.count() == num_celebs
1074  
-True
1075  
-
1076  
-Bug #8283 -- Checking that applying filters after a disjunction works correctly.
1077  
->>> (ExtraInfo.objects.filter(note=n1)|ExtraInfo.objects.filter(info='e2')).filter(note=n1)
1078  
-[<ExtraInfo: e1>]
1079  
->>> (ExtraInfo.objects.filter(info='e2')|ExtraInfo.objects.filter(note=n1)).filter(note=n1)
1080  
-[<ExtraInfo: e1>]
1081  
-
1082  
-Pickling of DateQuerySets used to fail
1083  
->>> qs = Item.objects.dates('created', 'month')
1084  
->>> _ = pickle.loads(pickle.dumps(qs))
1085  
-
1086  
-Bug #8683 -- raise proper error when a DateQuerySet gets passed a wrong type of field
1087  
->>> Item.objects.dates('name', 'month')
1088  
-Traceback (most recent call last):
1089  
-...
1090  
-AssertionError: 'name' isn't a DateField.
1091  
-
1092  
-Bug #8597: regression tests for case-insensitive comparisons
1093  
->>> _ = Item.objects.create(name="a_b", created=datetime.datetime.now(), creator=a2, note=n1)
1094  
->>> _ = Item.objects.create(name="x%y", created=datetime.datetime.now(), creator=a2, note=n1)
1095  
->>> Item.objects.filter(name__iexact="A_b")
1096  
-[<Item: a_b>]
1097  
->>> Item.objects.filter(name__iexact="x%Y")
1098  
-[<Item: x%y>]
1099  
->>> Item.objects.filter(name__istartswith="A_b")
1100  
-[<Item: a_b>]
1101  
->>> Item.objects.filter(name__iendswith="A_b")
1102  
-[<Item: a_b>]
1103  
-
1104  
-Bug #7302: reserved names are appropriately escaped
1105  
->>> _ = ReservedName.objects.create(name='a',order=42)
1106  
->>> _ = ReservedName.objects.create(name='b',order=37)
1107  
->>> ReservedName.objects.all().order_by('order')
1108  
-[<ReservedName: b>, <ReservedName: a>]
1109  
->>> ReservedName.objects.extra(select={'stuff':'name'}, order_by=('order','stuff'))
1110  
-[<ReservedName: b>, <ReservedName: a>]
1111  
-
1112  
-Bug #8439 -- complex combinations of conjunctions, disjunctions and nullable
1113  
-relations.
1114  
->>> Author.objects.filter(Q(item__note__extrainfo=e2)|Q(report=r1, name='xyz'))
1115  
-[<Author: a2>]
1116  
->>> Author.objects.filter(Q(report=r1, name='xyz')|Q(item__note__extrainfo=e2))
1117  
-[<Author: a2>]
1118  
->>> Annotation.objects.filter(Q(tag__parent=t1)|Q(notes__note='n1', name='a1'))
1119  
-[<Annotation: a1>]
1120  
->>> xx = ExtraInfo.objects.create(info='xx', note=n3)
1121  
->>> Note.objects.filter(Q(extrainfo__author=a1)|Q(extrainfo=xx))
1122  
-[<Note: n1>, <Note: n3>]
1123  
->>> xx.delete()
1124  
->>> q = Note.objects.filter(Q(extrainfo__author=a1)|Q(extrainfo=xx)).query
1125  
->>> len([x[2] for x in q.alias_map.values() if x[2] == q.LOUTER and q.alias_refcount[x[1]]])
1126  
-1
1127  
-
1128  
-Make sure bump_prefix() (an internal Query method) doesn't (re-)break. It's
1129  
-sufficient that this query runs without error.
1130  
->>> qs = Tag.objects.values_list('id', flat=True).order_by('id')
1131  
->>> qs.query.bump_prefix()
1132  
->>> list(qs)
1133  
-[1, 2, 3, 4, 5]
1134  
-
1135  
-Calling order_by() with no parameters removes any existing ordering on the
1136  
-model. But it should still be possible to add new ordering after that.
1137  
->>> qs = Author.objects.order_by().order_by('name')
1138  
->>> 'ORDER BY' in qs.query.get_compiler(qs.db).as_sql()[0]
1139  
-True
1140  
-
1141  
-Incorrect SQL was being generated for certain types of exclude() queries that
1142  
-crossed multi-valued relations (#8921, #9188 and some pre-emptively discovered
1143  
-cases).
1144  
-
1145  
->>> PointerA.objects.filter(connection__pointerb__id=1)
1146  
-[]
1147  
->>> PointerA.objects.exclude(connection__pointerb__id=1)
1148  
-[]
1149  
-
1150  
->>> Tag.objects.exclude(children=None)
1151  
-[<Tag: t1>, <Tag: t3>]
1152  
-
1153  
-# This example is tricky because the parent could be NULL, so only checking
1154  
-# parents with annotations omits some results (tag t1, in this case).
1155  
->>> Tag.objects.exclude(parent__annotation__name="a1")
1156  
-[<Tag: t1>, <Tag: t4>, <Tag: t5>]
1157  
-
1158  
-# The annotation->tag link is single values and tag->children links is
1159  
-# multi-valued. So we have to split the exclude filter in the middle and then
1160  
-# optimise the inner query without losing results.
1161  
->>> Annotation.objects.exclude(tag__children__name="t2")
1162  
-[<Annotation: a2>]
1163  
-
1164  
-Nested queries are possible (although should be used with care, since they have
1165  
-performance problems on backends like MySQL.
1166  
-
1167  
->>> Annotation.objects.filter(notes__in=Note.objects.filter(note="n1"))
1168  
-[<Annotation: a1>]
1169  
-
1170  
-Nested queries should not evaluate the inner query as part of constructing the
1171  
-SQL (so we should see a nested query here, indicated by two "SELECT" calls).
1172  
->>> qs = Annotation.objects.filter(notes__in=Note.objects.filter(note="xyzzy"))
1173  
->>> qs.query.get_compiler(qs.db).as_sql()[0].count('SELECT')
1174  
-2
1175  
-
1176  
-Bug #10181 -- Avoid raising an EmptyResultSet if an inner query is provably
1177  
-empty (and hence, not executed).
1178  
->>> Tag.objects.filter(id__in=Tag.objects.filter(id__in=[]))
1179  
-[]
1180  
-
1181  
-Bug #9997 -- If a ValuesList or Values queryset is passed as an inner query, we
1182  
-make sure it's only requesting a single value and use that as the thing to
1183  
-select.
1184  
->>> Tag.objects.filter(name__in=Tag.objects.filter(parent=t1).values('name'))
1185  
-[<Tag: t2>, <Tag: t3>]
1186  
-
1187  
-# Multi-valued values() and values_list() querysets should raise errors.
1188  
->>> Tag.objects.filter(name__in=Tag.objects.filter(parent=t1).values('name', 'id'))
1189  
-Traceback (most recent call last):
1190  
-...
1191  
-TypeError: Cannot use a multi-field ValuesQuerySet as a filter value.
1192  
->>> Tag.objects.filter(name__in=Tag.objects.filter(parent=t1).values_list('name', 'id'))
1193  
-Traceback (most recent call last):
1194  
-...
1195  
-TypeError: Cannot use a multi-field ValuesListQuerySet as a filter value.
1196  
-
1197  
-Bug #9985 -- qs.values_list(...).values(...) combinations should work.
1198  
->>> Note.objects.values_list("note", flat=True).values("id").order_by("id")
1199  
-[{'id': 1}, {'id': 2}, {'id': 3}]
1200  
->>> Annotation.objects.filter(notes__in=Note.objects.filter(note="n1").values_list('note').values('id'))
1201  
-[<Annotation: a1>]
1202  
-
1203  
-Bug #10028 -- ordering by model related to nullable relations(!) should use
1204  
-outer joins, so that all results are included.
1205  
->>> _ = Plaything.objects.create(name="p1")
1206  
->>> Plaything.objects.all()
1207  
-[<Plaything: p1>]
1208  
-
1209  
-Bug #10205 -- When bailing out early because of an empty "__in" filter, we need
1210  
-to set things up correctly internally so that subqueries can continue properly.
1211  
->>> Tag.objects.filter(name__in=()).update(name="foo")
1212  
-0
1213  
-
1214  
-Bug #10432 (see also the Python 2.4+ tests for this, below). Testing an empty
1215  
-"__in" filter with a generator as the value.
1216  
->>> def f():
1217  
-...     return iter([])
1218  
->>> n_obj = Note.objects.all()[0]
1219  
->>> def g():
1220  
-...     for i in [n_obj.pk]:
1221  
-...         yield i
1222  
->>> Note.objects.filter(pk__in=f())
1223  
-[]
1224  
->>> list(Note.objects.filter(pk__in=g())) == [n_obj]
1225  
-True
1226  
-
1227  
-Make sure that updates which only filter on sub-tables don't inadvertently
1228  
-update the wrong records (bug #9848).
1229  
-
1230  
-# Make sure that the IDs from different tables don't happen to match.
1231  
->>> Ranking.objects.filter(author__name='a1')
1232  
-[<Ranking: 3: a1>]
1233  
->>> Ranking.objects.filter(author__name='a1').update(rank='4')
1234  
-1
1235  
->>> r = Ranking.objects.filter(author__name='a1')[0]
1236  
->>> r.id != r.author.id
1237  
-True
1238  
->>> r.rank
1239  
-4
1240  
->>> r.rank = 3
1241  
->>> r.save()
1242  
->>> Ranking.objects.all()
1243  
-[<Ranking: 3: a1>, <Ranking: 2: a2>, <Ranking: 1: a3>]
1244  
-
1245  
-# Regression test for #10742:
1246  
-# Queries used in an __in clause don't execute subqueries
1247  
-
1248  
->>> subq = Author.objects.filter(num__lt=3000)
1249  
->>> qs = Author.objects.filter(pk__in=subq)
1250  
->>> list(qs)
1251  
-[<Author: a1>, <Author: a2>]
1252  
-
1253  
-# The subquery result cache should not be populated
1254  
->>> subq._result_cache is None
1255  
-True
1256  
-
1257  
->>> subq = Author.objects.filter(num__lt=3000)
1258  
->>> qs = Author.objects.exclude(pk__in=subq)
1259  
->>> list(qs)
1260  
-[<Author: a3>, <Author: a4>]
1261  
-
1262  
-# The subquery result cache should not be populated
1263  
->>> subq._result_cache is None
1264  
-True
1265  
-
1266  
->>> subq = Author.objects.filter(num__lt=3000)
1267  
->>> list(Author.objects.filter(Q(pk__in=subq) & Q(name='a1')))
1268  
-[<Author: a1>]
1269  
-
1270  
-# The subquery result cache should not be populated
1271  
->>> subq._result_cache is None
1272  
-True
1273  
-
1274  
-"""}
1275  
-
1276  
-# In Python 2.6 beta releases, exceptions raised in __len__
1277  
-# are swallowed (Python issue 1242657), so these cases return an empty list,
1278  
-# rather than raising an exception. Not a lot we can do about that,
1279  
-# unfortunately, due to the way Python handles list() calls internally. Thus,
1280  
-# we skip the tests for Python 2.6.
1281  
-if sys.version_info < (2, 6):
1282  
-    __test__["API_TESTS"] += """
1283  
-# If you're not careful, it's possible to introduce infinite loops via default
1284  
-# ordering on foreign keys in a cycle. We detect that.
1285  
->>> LoopX.objects.all()
1286  
-Traceback (most recent call last):
1287  
-...
1288  
-FieldError: Infinite loop caused by ordering.
1289  
-
1290  
->>> LoopZ.objects.all()
1291  
-Traceback (most recent call last):
1292  
-...
1293  
-FieldError: Infinite loop caused by ordering.
1294  
-
1295  
-# Note that this doesn't cause an infinite loop, since the default ordering on
1296  
-# the Tag model is empty (and thus defaults to using "id" for the related
1297  
-# field).
1298  
->>> len(Tag.objects.order_by('parent'))
1299  
-5
1300  
-
1301  
-# ... but you can still order in a non-recursive fashion amongst linked fields
1302  
-# (the previous test failed because the default ordering was recursive).
1303  
->>> LoopX.objects.all().order_by('y__x__y__x__id')
1304  
-[]
1305  
-
1306  
-"""
1307  
-
1308  
-
1309  
-# In Oracle, we expect a null CharField to return u'' instead of None.
1310  
-if settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] == "django.db.backends.oracle":
1311  
-    __test__["API_TESTS"] = __test__["API_TESTS"].replace("<NONE_OR_EMPTY_UNICODE>", "u''")
1312  
-else:
1313  
-    __test__["API_TESTS"] = __test__["API_TESTS"].replace("<NONE_OR_EMPTY_UNICODE>", "None")
1314  
-
1315  
-
1316  
-if settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] == "django.db.backends.mysql":
1317  
-    __test__["API_TESTS"] += """
1318  
-When grouping without specifying ordering, we add an explicit "ORDER BY NULL"
1319  
-portion in MySQL to prevent unnecessary sorting.
1320  
-
1321