~ubuntu-branches/ubuntu/quantal/python-django/quantal-security

« back to all changes in this revision

Viewing changes to tests/regressiontests/queries/models.py

  • Committer: Bazaar Package Importer
  • Author(s): Chris Lamb
  • Date: 2010-05-21 07:52:55 UTC
  • mfrom: (1.3.6 upstream)
  • mto: This revision was merged to the branch mainline in revision 28.
  • Revision ID: james.westby@ubuntu.com-20100521075255-ii78v1dyfmyu3uzx
Tags: upstream-1.2
ImportĀ upstreamĀ versionĀ 1.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
5
5
import datetime
6
6
import pickle
7
7
import sys
 
8
import threading
8
9
 
9
10
from django.conf import settings
10
 
from django.db import models
11
 
from django.db.models.query import Q, ITER_CHUNK_SIZE
12
 
 
13
 
# Python 2.3 doesn't have sorted()
14
 
try:
15
 
    sorted
16
 
except NameError:
17
 
    from django.utils.itercompat import sorted
 
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
18
14
 
19
15
class DumbCategory(models.Model):
20
16
    pass
44
40
    def __unicode__(self):
45
41
        return self.note
46
42
 
 
43
    def __init__(self, *args, **kwargs):
 
44
        super(Note, self).__init__(*args, **kwargs)
 
45
        # Regression for #13227 -- having an attribute that
 
46
        # is unpickleable doesn't stop you from cloning queries
 
47
        # that use objects of that type as an argument.
 
48
        self.lock = threading.Lock()
 
49
 
47
50
class Annotation(models.Model):
48
51
    name = models.CharField(max_length=10)
49
52
    tag = models.ForeignKey(Tag)
276
279
 
277
280
 
278
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
 
279
292
>>> generic = NamedCategory.objects.create(name="Generic")
280
293
>>> t1 = Tag.objects.create(name='t1', category=generic)
281
294
>>> t2 = Tag.objects.create(name='t2', parent=t1, category=generic)
283
296
>>> t4 = Tag.objects.create(name='t4', parent=t3)
284
297
>>> t5 = Tag.objects.create(name='t5', parent=t3)
285
298
 
286
 
>>> n1 = Note.objects.create(note='n1', misc='foo')
287
 
>>> n2 = Note.objects.create(note='n2', misc='bar')
288
 
>>> n3 = Note.objects.create(note='n3', misc='foo')
 
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)
289
302
 
290
303
>>> ann1 = Annotation.objects.create(name='a1', tag=t1)
291
304
>>> ann1.notes.add(n1)
417
430
>>> Number.objects.filter(Q(num__gt=7) & Q(num__lt=12) | Q(num__lt=4))
418
431
[<Number: 8>]
419
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
 
420
472
Bug #7872
421
473
Another variation on the disjunctive filtering theme.
422
474
 
755
807
>>> Item.objects.dates('created', 'day')[0]
756
808
datetime.datetime(2007, 12, 19, 0, 0)
757
809
 
758
 
Bug #7087 -- dates with extra select columns
 
810
Bug #7087/#12242 -- dates with extra select columns
759
811
>>> Item.objects.dates('created', 'day').extra(select={'a': 1})
760
812
[datetime.datetime(2007, 12, 19, 0, 0), datetime.datetime(2007, 12, 20, 0, 0)]
761
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
 
762
824
Bug #7155 -- nullable dates
763
825
>>> Item.objects.dates('modified', 'day')
764
826
[datetime.datetime(2007, 12, 19, 0, 0)]
812
874
 
813
875
Bug #7045 -- extra tables used to crash SQL construction on the second use.
814
876
>>> qs = Ranking.objects.extra(tables=['django_site'])
815
 
>>> s = qs.query.as_sql()
816
 
>>> s = qs.query.as_sql()   # test passes if this doesn't raise an exception.
 
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.
817
879
 
818
880
Bug #7098 -- Make sure semi-deprecated ordering by related models syntax still
819
881
works.
902
964
tricky thing here is to ensure that we do the related selections properly after
903
965
unpickling.
904
966
>>> qs = Item.objects.select_related()
905
 
>>> query = qs.query.as_sql()[0]
 
967
>>> query = qs.query.get_compiler(qs.db).as_sql()[0]
906
968
>>> query2 = pickle.loads(pickle.dumps(qs.query))
907
 
>>> query2.as_sql()[0] == query
 
969
>>> query2.get_compiler(qs.db).as_sql()[0] == query
908
970
True
909
971
 
910
972
Check pickling of deferred-loading querysets
959
1021
...     break
960
1022
True
961
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
 
962
1056
Bug #7791 -- there were "issues" when ordering and distinct-ing on fields
963
1057
related via ForeignKeys.
964
1058
>>> len(Note.objects.order_by('extrainfo__info').distinct())
1041
1135
Calling order_by() with no parameters removes any existing ordering on the
1042
1136
model. But it should still be possible to add new ordering after that.
1043
1137
>>> qs = Author.objects.order_by().order_by('name')
1044
 
>>> 'ORDER BY' in qs.query.as_sql()[0]
 
1138
>>> 'ORDER BY' in qs.query.get_compiler(qs.db).as_sql()[0]
1045
1139
True
1046
1140
 
1047
1141
Incorrect SQL was being generated for certain types of exclude() queries that
1075
1169
 
1076
1170
Nested queries should not evaluate the inner query as part of constructing the
1077
1171
SQL (so we should see a nested query here, indicated by two "SELECT" calls).
1078
 
>>> Annotation.objects.filter(notes__in=Note.objects.filter(note="xyzzy")).query.as_sql()[0].count('SELECT')
 
1172
>>> qs = Annotation.objects.filter(notes__in=Note.objects.filter(note="xyzzy"))
 
1173
>>> qs.query.get_compiler(qs.db).as_sql()[0].count('SELECT')
1079
1174
2
1080
1175
 
1081
1176
Bug #10181 -- Avoid raising an EmptyResultSet if an inner query is provably
1178
1273
 
1179
1274
"""}
1180
1275
 
1181
 
# In Python 2.3 and the Python 2.6 beta releases, exceptions raised in __len__
 
1276
# In Python 2.6 beta releases, exceptions raised in __len__
1182
1277
# are swallowed (Python issue 1242657), so these cases return an empty list,
1183
1278
# rather than raising an exception. Not a lot we can do about that,
1184
1279
# unfortunately, due to the way Python handles list() calls internally. Thus,
1185
 
# we skip the tests for Python 2.3 and 2.6.
1186
 
if (2, 4) <= sys.version_info < (2, 6):
 
1280
# we skip the tests for Python 2.6.
 
1281
if sys.version_info < (2, 6):
1187
1282
    __test__["API_TESTS"] += """
1188
1283
# If you're not careful, it's possible to introduce infinite loops via default
1189
1284
# ordering on foreign keys in a cycle. We detect that.
1212
1307
 
1213
1308
 
1214
1309
# In Oracle, we expect a null CharField to return u'' instead of None.
1215
 
if settings.DATABASE_ENGINE == "oracle":
 
1310
if settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] == "django.db.backends.oracle":
1216
1311
    __test__["API_TESTS"] = __test__["API_TESTS"].replace("<NONE_OR_EMPTY_UNICODE>", "u''")
1217
1312
else:
1218
1313
    __test__["API_TESTS"] = __test__["API_TESTS"].replace("<NONE_OR_EMPTY_UNICODE>", "None")
1219
1314
 
1220
1315
 
1221
 
if settings.DATABASE_ENGINE == "mysql":
 
1316
if settings.DATABASES[DEFAULT_DB_ALIAS]['ENGINE'] == "django.db.backends.mysql":
1222
1317
    __test__["API_TESTS"] += """
1223
1318
When grouping without specifying ordering, we add an explicit "ORDER BY NULL"
1224
1319
portion in MySQL to prevent unnecessary sorting.
1225
1320
 
1226
1321
>>> query = Tag.objects.values_list('parent_id', flat=True).order_by().query
1227
1322
>>> query.group_by = ['parent_id']
1228
 
>>> sql = query.as_sql()[0]
 
1323
>>> sql = query.get_compiler(DEFAULT_DB_ALIAS).as_sql()[0]
1229
1324
>>> fragment = "ORDER BY "
1230
1325
>>> pos = sql.find(fragment)
1231
1326
>>> sql.find(fragment, pos + 1) == -1