9
10
from django.conf import settings
10
from django.db import models
11
from django.db.models.query import Q, ITER_CHUNK_SIZE
13
# Python 2.3 doesn't have sorted()
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
19
15
class DumbCategory(models.Model):
44
40
def __unicode__(self):
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()
47
50
class Annotation(models.Model):
48
51
name = models.CharField(max_length=10)
49
52
tag = models.ForeignKey(Tag)
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()
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']
290
>>> settings.DEBUG = False
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)
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)
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))
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)
439
>>> Number.objects.filter(num__gt=12)
441
>>> Number.objects.filter(num__gt=12.0)
443
>>> Number.objects.filter(num__gt=12.1)
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)
453
>>> Number.objects.filter(num__gte=12)
455
>>> Number.objects.filter(num__gte=12.0)
457
>>> Number.objects.filter(num__gte=12.1)
459
>>> Number.objects.filter(num__gte=12.9)
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>]
421
473
Another variation on the disjunctive filtering theme.
755
807
>>> Item.objects.dates('created', 'day')[0]
756
808
datetime.datetime(2007, 12, 19, 0, 0)
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)]
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)]
818
>>> Item.objects.dates('created', 'day').extra(where=['name=%s'], params=[name])
819
[datetime.datetime(2007, 12, 19, 0, 0)]
821
>>> Item.objects.extra(where=['name=%s'], params=[name]).dates('created', 'day')
822
[datetime.datetime(2007, 12, 19, 0, 0)]
762
824
Bug #7155 -- nullable dates
763
825
>>> Item.objects.dates('modified', 'day')
764
826
[datetime.datetime(2007, 12, 19, 0, 0)]
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.
818
880
Bug #7098 -- Make sure semi-deprecated ordering by related models syntax still
902
964
tricky thing here is to ensure that we do the related selections properly after
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
910
972
Check pickling of deferred-loading querysets
1024
Bug #7235 -- an EmptyQuerySet should not raise exceptions if it is filtered.
1025
>>> q = EmptyQuerySet()
1032
>>> q.complex_filter({'pk': 1})
1034
>>> q.select_related('spam', 'eggs')
1036
>>> q.annotate(Count('eggs'))
1038
>>> q.order_by('-pub_date', 'headline')
1042
>>> q.extra(select={'is_recent': "pub_date > '2006-01-01'"})
1044
>>> q.query.low_mark = 1
1045
>>> q.extra(select={'is_recent': "pub_date > '2006-01-01'"})
1046
Traceback (most recent call last):
1048
AssertionError: Cannot change a query once a slice has been taken
1051
>>> q.defer('spam', 'eggs')
1053
>>> q.only('spam', 'eggs')
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]
1047
1141
Incorrect SQL was being generated for certain types of exclude() queries that
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')
1081
1176
Bug #10181 -- Avoid raising an EmptyResultSet if an inner query is provably
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.
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''")
1218
1313
__test__["API_TESTS"] = __test__["API_TESTS"].replace("<NONE_OR_EMPTY_UNICODE>", "None")
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.
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