Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
"""
Various complex queries that have been problematic in the past .
"""
import datetime
2008-06-27 11:27:20 +08:00
import pickle
2008-07-17 07:55:10 +08:00
import sys
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
2008-12-10 13:19:27 +08:00
from django . conf import settings
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
from django . db import models
2008-07-16 02:47:32 +08:00
from django . db . models . query import Q , ITER_CHUNK_SIZE
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
2008-07-13 16:48:18 +08:00
# Python 2.3 doesn't have sorted()
try :
sorted
except NameError :
from django . utils . itercompat import sorted
2008-07-16 02:47:32 +08:00
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
class Tag ( models . Model ) :
name = models . CharField ( max_length = 10 )
2008-06-29 11:01:46 +08:00
parent = models . ForeignKey ( ' self ' , blank = True , null = True ,
related_name = ' children ' )
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
2008-08-15 11:36:18 +08:00
class Meta :
ordering = [ ' name ' ]
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
def __unicode__ ( self ) :
return self . name
class Note ( models . Model ) :
note = models . CharField ( max_length = 100 )
misc = models . CharField ( max_length = 10 )
class Meta :
ordering = [ ' note ' ]
def __unicode__ ( self ) :
return self . note
2008-06-29 11:01:46 +08:00
class Annotation ( models . Model ) :
name = models . CharField ( max_length = 10 )
tag = models . ForeignKey ( Tag )
notes = models . ManyToManyField ( Note )
def __unicode__ ( self ) :
return self . name
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
class ExtraInfo ( models . Model ) :
info = models . CharField ( max_length = 100 )
note = models . ForeignKey ( Note )
class Meta :
ordering = [ ' info ' ]
def __unicode__ ( self ) :
return self . info
class Author ( models . Model ) :
name = models . CharField ( max_length = 10 )
num = models . IntegerField ( unique = True )
extra = models . ForeignKey ( ExtraInfo )
def __unicode__ ( self ) :
return self . name
class Item ( models . Model ) :
name = models . CharField ( max_length = 10 )
created = models . DateTimeField ( )
2008-06-25 21:38:06 +08:00
modified = models . DateTimeField ( blank = True , null = True )
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
tags = models . ManyToManyField ( Tag , blank = True , null = True )
creator = models . ForeignKey ( Author )
note = models . ForeignKey ( Note )
class Meta :
ordering = [ ' -note ' , ' name ' ]
def __unicode__ ( self ) :
return self . name
class Report ( models . Model ) :
name = models . CharField ( max_length = 10 )
2008-06-26 09:01:21 +08:00
creator = models . ForeignKey ( Author , to_field = ' num ' , null = True )
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
def __unicode__ ( self ) :
return self . name
class Ranking ( models . Model ) :
rank = models . IntegerField ( )
author = models . ForeignKey ( Author )
class Meta :
# A complex ordering specification. Should stress the system a bit.
ordering = ( ' author__extra__note ' , ' author__name ' , ' rank ' )
def __unicode__ ( self ) :
return ' %d : %s ' % ( self . rank , self . author . name )
class Cover ( models . Model ) :
title = models . CharField ( max_length = 50 )
item = models . ForeignKey ( Item )
class Meta :
ordering = [ ' item ' ]
def __unicode__ ( self ) :
return self . title
class Number ( models . Model ) :
num = models . IntegerField ( )
def __unicode__ ( self ) :
return unicode ( self . num )
2008-06-26 18:50:25 +08:00
# Symmetrical m2m field with a normal field using the reverse accesor name
# ("valid").
class Valid ( models . Model ) :
valid = models . CharField ( max_length = 10 )
parent = models . ManyToManyField ( ' self ' )
class Meta :
ordering = [ ' valid ' ]
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
# Some funky cross-linked models for testing a couple of infinite recursion
# cases.
class X ( models . Model ) :
y = models . ForeignKey ( ' Y ' )
class Y ( models . Model ) :
x1 = models . ForeignKey ( X , related_name = ' y1 ' )
# Some models with a cycle in the default ordering. This would be bad if we
# didn't catch the infinite loop.
class LoopX ( models . Model ) :
y = models . ForeignKey ( ' LoopY ' )
class Meta :
ordering = [ ' y ' ]
class LoopY ( models . Model ) :
x = models . ForeignKey ( LoopX )
class Meta :
ordering = [ ' x ' ]
class LoopZ ( models . Model ) :
z = models . ForeignKey ( ' self ' )
class Meta :
ordering = [ ' z ' ]
2008-04-28 19:51:16 +08:00
# A model and custom default manager combination.
class CustomManager ( models . Manager ) :
def get_query_set ( self ) :
2008-04-29 01:31:08 +08:00
qs = super ( CustomManager , self ) . get_query_set ( )
2008-06-26 11:11:32 +08:00
return qs . filter ( public = True , tag__name = ' t1 ' )
2008-04-28 19:51:16 +08:00
class ManagedModel ( models . Model ) :
data = models . CharField ( max_length = 10 )
tag = models . ForeignKey ( Tag )
2008-06-26 11:11:32 +08:00
public = models . BooleanField ( default = True )
2008-04-28 19:51:16 +08:00
objects = CustomManager ( )
normal_manager = models . Manager ( )
def __unicode__ ( self ) :
return self . data
2008-06-26 09:02:11 +08:00
# An inter-related setup with multiple paths from Child to Detail.
class Detail ( models . Model ) :
data = models . CharField ( max_length = 10 )
class MemberManager ( models . Manager ) :
def get_query_set ( self ) :
return super ( MemberManager , self ) . get_query_set ( ) . select_related ( " details " )
class Member ( models . Model ) :
name = models . CharField ( max_length = 10 )
details = models . OneToOneField ( Detail , primary_key = True )
objects = MemberManager ( )
class Child ( models . Model ) :
person = models . OneToOneField ( Member , primary_key = True )
parent = models . ForeignKey ( Member , related_name = " children " )
2008-06-29 19:15:48 +08:00
# Custom primary keys interfered with ordering in the past.
class CustomPk ( models . Model ) :
name = models . CharField ( max_length = 10 , primary_key = True )
extra = models . CharField ( max_length = 10 )
class Meta :
ordering = [ ' name ' , ' extra ' ]
class Related ( models . Model ) :
custom = models . ForeignKey ( CustomPk )
2008-07-27 12:18:52 +08:00
# An inter-related setup with a model subclass that has a nullable
# path to another model, and a return path from that model.
class Celebrity ( models . Model ) :
name = models . CharField ( " Name " , max_length = 20 )
greatest_fan = models . ForeignKey ( " Fan " , null = True , unique = True )
class TvChef ( Celebrity ) :
pass
class Fan ( models . Model ) :
fan_of = models . ForeignKey ( Celebrity )
2008-07-28 02:16:17 +08:00
# Multiple foreign keys
class LeafA ( models . Model ) :
data = models . CharField ( max_length = 10 )
def __unicode__ ( self ) :
return self . data
class LeafB ( models . Model ) :
data = models . CharField ( max_length = 10 )
class Join ( models . Model ) :
a = models . ForeignKey ( LeafA )
b = models . ForeignKey ( LeafB )
2008-04-28 19:51:16 +08:00
2008-09-01 20:07:26 +08:00
class ReservedName ( models . Model ) :
name = models . CharField ( max_length = 20 )
order = models . IntegerField ( )
2008-09-02 10:16:41 +08:00
2008-09-01 20:07:26 +08:00
def __unicode__ ( self ) :
return self . name
2008-09-02 10:16:41 +08:00
2008-12-07 13:48:01 +08:00
# A simpler shared-foreign-key setup that can expose some problems.
class SharedConnection ( models . Model ) :
data = models . CharField ( max_length = 10 )
class PointerA ( models . Model ) :
connection = models . ForeignKey ( SharedConnection )
class PointerB ( models . Model ) :
connection = models . ForeignKey ( SharedConnection )
2009-02-28 10:59:40 +08:00
# Multi-layer ordering
class SingleObject ( models . Model ) :
name = models . CharField ( max_length = 10 )
class Meta :
ordering = [ ' name ' ]
def __unicode__ ( self ) :
return self . name
class RelatedObject ( models . Model ) :
single = models . ForeignKey ( SingleObject )
class Meta :
ordering = [ ' single ' ]
class Plaything ( models . Model ) :
name = models . CharField ( max_length = 10 )
others = models . ForeignKey ( RelatedObject , null = True )
class Meta :
ordering = [ ' others ' ]
def __unicode__ ( self ) :
return self . name
2008-12-07 13:48:01 +08:00
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
__test__ = { ' API_TESTS ' : """
2008-06-29 11:07:45 +08:00
>> > t1 = Tag . objects . create ( name = ' t1 ' )
>> > t2 = Tag . objects . create ( name = ' t2 ' , parent = t1 )
>> > t3 = Tag . objects . create ( name = ' t3 ' , parent = t1 )
>> > t4 = Tag . objects . create ( name = ' t4 ' , parent = t3 )
>> > t5 = Tag . objects . create ( name = ' t5 ' , parent = t3 )
>> > n1 = Note . objects . create ( note = ' n1 ' , misc = ' foo ' )
>> > n2 = Note . objects . create ( note = ' n2 ' , misc = ' bar ' )
>> > n3 = Note . objects . create ( note = ' n3 ' , misc = ' foo ' )
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
2008-09-02 10:16:41 +08:00
>> > ann1 = Annotation . objects . create ( name = ' a1 ' , tag = t1 )
>> > ann1 . notes . add ( n1 )
>> > ann2 = Annotation . objects . create ( name = ' a2 ' , tag = t4 )
>> > ann2 . notes . add ( n2 , n3 )
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
Create these out of order so that sorting by ' id ' will be different to sorting
by ' info ' . Helps detect some problems later .
2008-06-29 11:07:45 +08:00
>> > e2 = ExtraInfo . objects . create ( info = ' e2 ' , note = n2 )
>> > e1 = ExtraInfo . objects . create ( info = ' e1 ' , note = n1 )
>> > a1 = Author . objects . create ( name = ' a1 ' , num = 1001 , extra = e1 )
>> > a2 = Author . objects . create ( name = ' a2 ' , num = 2002 , extra = e1 )
>> > a3 = Author . objects . create ( name = ' a3 ' , num = 3003 , extra = e2 )
>> > a4 = Author . objects . create ( name = ' a4 ' , num = 4004 , extra = e2 )
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
>> > time1 = datetime . datetime ( 2007 , 12 , 19 , 22 , 25 , 0 )
>> > time2 = datetime . datetime ( 2007 , 12 , 19 , 21 , 0 , 0 )
>> > time3 = datetime . datetime ( 2007 , 12 , 20 , 22 , 25 , 0 )
>> > time4 = datetime . datetime ( 2007 , 12 , 20 , 21 , 0 , 0 )
2008-06-29 11:07:45 +08:00
>> > i1 = Item . objects . create ( name = ' one ' , created = time1 , modified = time1 , creator = a1 , note = n3 )
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
>> > i1 . tags = [ t1 , t2 ]
2008-06-29 11:07:45 +08:00
>> > i2 = Item . objects . create ( name = ' two ' , created = time2 , creator = a2 , note = n2 )
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
>> > i2 . tags = [ t1 , t3 ]
2008-06-29 11:07:45 +08:00
>> > i3 = Item . objects . create ( name = ' three ' , created = time3 , creator = a2 , note = n3 )
>> > i4 = Item . objects . create ( name = ' four ' , created = time4 , creator = a4 , note = n3 )
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
>> > i4 . tags = [ t4 ]
2008-06-29 11:07:45 +08:00
>> > r1 = Report . objects . create ( name = ' r1 ' , creator = a1 )
>> > r2 = Report . objects . create ( name = ' r2 ' , creator = a3 )
>> > r3 = Report . objects . create ( name = ' r3 ' )
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
Ordering by ' rank ' gives us rank2 , rank1 , rank3 . Ordering by the Meta . ordering
will be rank3 , rank2 , rank1 .
2008-06-29 11:07:45 +08:00
>> > rank1 = Ranking . objects . create ( rank = 2 , author = a2 )
>> > rank2 = Ranking . objects . create ( rank = 1 , author = a3 )
>> > rank3 = Ranking . objects . create ( rank = 3 , author = a1 )
>> > c1 = Cover . objects . create ( title = " first " , item = i4 )
>> > c2 = Cover . objects . create ( title = " second " , item = i2 )
>> > num1 = Number . objects . create ( num = 4 )
>> > num2 = Number . objects . create ( num = 8 )
>> > num3 = Number . objects . create ( num = 12 )
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
Bug #1050
>> > Item . objects . filter ( tags__isnull = True )
[ < Item : three > ]
>> > Item . objects . filter ( tags__id__isnull = True )
[ < Item : three > ]
Bug #1801
>> > Author . objects . filter ( item = i2 )
[ < Author : a2 > ]
>> > Author . objects . filter ( item = i3 )
[ < Author : a2 > ]
>> > Author . objects . filter ( item = i2 ) & Author . objects . filter ( item = i3 )
[ < Author : a2 > ]
Bug #2306
Checking that no join types are " left outer " joins .
>> > query = Item . objects . filter ( tags = t2 ) . query
>> > query . LOUTER not in [ x [ 2 ] for x in query . alias_map . values ( ) ]
True
>> > Item . objects . filter ( Q ( tags = t1 ) ) . order_by ( ' name ' )
[ < Item : one > , < Item : two > ]
>> > Item . objects . filter ( Q ( tags = t1 ) ) . filter ( Q ( tags = t2 ) )
[ < Item : one > ]
>> > Item . objects . filter ( Q ( tags = t1 ) ) . filter ( Q ( creator__name = ' fred ' ) | Q ( tags = t2 ) )
[ < Item : one > ]
Each filter call is processed " at once " against a single table , so this is
different from the previous example as it tries to find tags that are two
things at once ( rather than two tags ) .
>> > Item . objects . filter ( Q ( tags = t1 ) & Q ( tags = t2 ) )
[ ]
>> > Item . objects . filter ( Q ( tags = t1 ) , Q ( creator__name = ' fred ' ) | Q ( tags = t2 ) )
[ ]
>> > qs = Author . objects . filter ( ranking__rank = 2 , ranking__id = rank1 . id )
>> > list ( qs )
[ < Author : a2 > ]
>> > qs . query . count_active_tables ( )
2
>> > qs = Author . objects . filter ( ranking__rank = 2 ) . filter ( ranking__id = rank1 . id )
>> > qs . query . count_active_tables ( )
3
Bug #4464
>> > Item . objects . filter ( tags = t1 ) . filter ( tags = t2 )
[ < Item : one > ]
>> > Item . objects . filter ( tags__in = [ t1 , t2 ] ) . distinct ( ) . order_by ( ' name ' )
[ < Item : one > , < Item : two > ]
>> > Item . objects . filter ( tags__in = [ t1 , t2 ] ) . filter ( tags = t3 )
[ < Item : two > ]
2008-10-11 01:15:58 +08:00
Make sure . distinct ( ) works with slicing ( this was broken in Oracle ) .
>> > Item . objects . filter ( tags__in = [ t1 , t2 ] ) . order_by ( ' name ' ) [ : 3 ]
[ < Item : one > , < Item : one > , < Item : two > ]
>> > Item . objects . filter ( tags__in = [ t1 , t2 ] ) . distinct ( ) . order_by ( ' name ' ) [ : 3 ]
[ < Item : one > , < Item : two > ]
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
Bug #2080, #3592
>> > Author . objects . filter ( item__name = ' one ' ) | Author . objects . filter ( name = ' a3 ' )
[ < Author : a1 > , < Author : a3 > ]
>> > Author . objects . filter ( Q ( item__name = ' one ' ) | Q ( name = ' a3 ' ) )
[ < Author : a1 > , < Author : a3 > ]
>> > Author . objects . filter ( Q ( name = ' a3 ' ) | Q ( item__name = ' one ' ) )
[ < Author : a1 > , < Author : a3 > ]
>> > Author . objects . filter ( Q ( item__name = ' three ' ) | Q ( report__name = ' r3 ' ) )
[ < Author : a2 > ]
Bug #4289
A slight variation on the above theme : restricting the choices by the lookup
constraints .
>> > Number . objects . filter ( num__lt = 4 )
[ ]
>> > Number . objects . filter ( num__gt = 8 , num__lt = 12 )
[ ]
>> > Number . objects . filter ( num__gt = 8 , num__lt = 13 )
[ < Number : 12 > ]
>> > Number . objects . filter ( Q ( num__lt = 4 ) | Q ( num__gt = 8 , num__lt = 12 ) )
[ ]
>> > Number . objects . filter ( Q ( num__gt = 8 , num__lt = 12 ) | Q ( num__lt = 4 ) )
[ ]
>> > Number . objects . filter ( Q ( num__gt = 8 ) & Q ( num__lt = 12 ) | Q ( num__lt = 4 ) )
[ ]
>> > Number . objects . filter ( Q ( num__gt = 7 ) & Q ( num__lt = 12 ) | Q ( num__lt = 4 ) )
[ < Number : 8 > ]
2008-07-28 02:16:17 +08:00
Bug #7872
Another variation on the disjunctive filtering theme .
# For the purposes of this regression test, it's important that there is no
# Join object releated to the LeafA we create.
>> > LeafA . objects . create ( data = ' first ' )
< LeafA : first >
>> > LeafA . objects . filter ( Q ( data = ' first ' ) | Q ( join__b__data = ' second ' ) )
[ < LeafA : first > ]
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
Bug #6074
Merging two empty result sets shouldn ' t leave a queryset with no constraints
( which would match everything ) .
>> > Author . objects . filter ( Q ( id__in = [ ] ) )
[ ]
>> > Author . objects . filter ( Q ( id__in = [ ] ) | Q ( id__in = [ ] ) )
[ ]
Bug #1878, #2939
>> > Item . objects . values ( ' creator ' ) . distinct ( ) . count ( )
3
# Create something with a duplicate 'name' so that we can test multi-column
# cases (which require some tricky SQL transformations under the covers).
>> > xx = Item ( name = ' four ' , created = time1 , creator = a2 , note = n1 )
>> > xx . save ( )
>> > Item . objects . exclude ( name = ' two ' ) . values ( ' creator ' , ' name ' ) . distinct ( ) . count ( )
4
>> > Item . objects . exclude ( name = ' two ' ) . extra ( select = { ' foo ' : ' %s ' } , select_params = ( 1 , ) ) . values ( ' creator ' , ' name ' , ' foo ' ) . distinct ( ) . count ( )
4
>> > Item . objects . exclude ( name = ' two ' ) . extra ( select = { ' foo ' : ' %s ' } , select_params = ( 1 , ) ) . values ( ' creator ' , ' name ' ) . distinct ( ) . count ( )
4
>> > xx . delete ( )
2008-06-29 19:50:04 +08:00
Bug #7323
>> > Item . objects . values ( ' creator ' , ' name ' ) . count ( )
4
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
Bug #2253
>> > q1 = Item . objects . order_by ( ' name ' )
>> > q2 = Item . objects . filter ( id = i1 . id )
>> > q1
[ < Item : four > , < Item : one > , < Item : three > , < Item : two > ]
>> > q2
[ < Item : one > ]
>> > ( q1 | q2 ) . order_by ( ' name ' )
[ < Item : four > , < Item : one > , < Item : three > , < Item : two > ]
>> > ( q1 & q2 ) . order_by ( ' name ' )
[ < Item : one > ]
# FIXME: This is difficult to fix and very much an edge case, so punt for now.
# # This is related to the order_by() tests, below, but the old bug exhibited
# # itself here (q2 was pulling too many tables into the combined query with the
# # new ordering, but only because we have evaluated q2 already).
# >>> len((q1 & q2).order_by('name').query.tables)
# 1
>> > q1 = Item . objects . filter ( tags = t1 )
>> > q2 = Item . objects . filter ( note = n3 , tags = t2 )
>> > q3 = Item . objects . filter ( creator = a4 )
>> > ( ( q1 & q2 ) | q3 ) . order_by ( ' name ' )
[ < Item : four > , < Item : one > ]
Bugs #4088, #4306
>> > Report . objects . filter ( creator = 1001 )
[ < Report : r1 > ]
>> > Report . objects . filter ( creator__num = 1001 )
[ < Report : r1 > ]
>> > Report . objects . filter ( creator__id = 1001 )
[ ]
>> > Report . objects . filter ( creator__id = a1 . id )
[ < Report : r1 > ]
>> > Report . objects . filter ( creator__name = ' a1 ' )
[ < Report : r1 > ]
Bug #4510
>> > Author . objects . filter ( report__name = ' r1 ' )
[ < Author : a1 > ]
2008-06-29 18:35:35 +08:00
Bug #7378
>> > a1 . report_set . all ( )
[ < Report : r1 > ]
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
Bug #5324, #6704
>> > Item . objects . filter ( tags__name = ' t4 ' )
[ < Item : four > ]
>> > Item . objects . exclude ( tags__name = ' t4 ' ) . order_by ( ' name ' ) . distinct ( )
[ < Item : one > , < Item : three > , < Item : two > ]
>> > Item . objects . exclude ( tags__name = ' t4 ' ) . order_by ( ' name ' ) . distinct ( ) . reverse ( )
[ < Item : two > , < Item : three > , < Item : one > ]
>> > Author . objects . exclude ( item__name = ' one ' ) . distinct ( ) . order_by ( ' name ' )
[ < Author : a2 > , < Author : a3 > , < Author : a4 > ]
# Excluding across a m2m relation when there is more than one related object
# associated was problematic.
>> > Item . objects . exclude ( tags__name = ' t1 ' ) . order_by ( ' name ' )
[ < Item : four > , < Item : three > ]
>> > Item . objects . exclude ( tags__name = ' t1 ' ) . exclude ( tags__name = ' t4 ' )
[ < Item : three > ]
# Excluding from a relation that cannot be NULL should not use outer joins.
>> > query = Item . objects . exclude ( creator__in = [ a1 , a2 ] ) . query
>> > query . LOUTER not in [ x [ 2 ] for x in query . alias_map . values ( ) ]
True
2008-07-28 02:16:17 +08:00
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 ) .
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
>> > qs = Author . objects . filter ( id = a1 . id ) . filter ( Q ( extra__note = n1 ) | Q ( item__note = n3 ) )
2008-07-28 02:16:17 +08:00
>> > len ( [ x [ 2 ] for x in qs . query . alias_map . values ( ) if x [ 2 ] == query . LOUTER and qs . query . alias_refcount [ x [ 1 ] ] ] )
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
1
The previous changes shouldn ' t affect nullable foreign key joins.
>> > Tag . objects . filter ( parent__isnull = True ) . order_by ( ' name ' )
[ < Tag : t1 > ]
>> > Tag . objects . exclude ( parent__isnull = True ) . order_by ( ' name ' )
[ < Tag : t2 > , < Tag : t3 > , < Tag : t4 > , < Tag : t5 > ]
>> > Tag . objects . exclude ( Q ( parent__name = ' t1 ' ) | Q ( parent__isnull = True ) ) . order_by ( ' name ' )
[ < Tag : t4 > , < Tag : t5 > ]
>> > Tag . objects . exclude ( Q ( parent__isnull = True ) | Q ( parent__name = ' t1 ' ) ) . order_by ( ' name ' )
[ < Tag : t4 > , < Tag : t5 > ]
>> > Tag . objects . exclude ( Q ( parent__parent__isnull = True ) ) . order_by ( ' name ' )
[ < Tag : t4 > , < Tag : t5 > ]
>> > Tag . objects . filter ( ~ Q ( parent__parent__isnull = True ) ) . order_by ( ' name ' )
[ < Tag : t4 > , < Tag : t5 > ]
Bug #2091
>> > t = Tag . objects . get ( name = ' t4 ' )
>> > Item . objects . filter ( tags__in = [ t ] )
[ < Item : four > ]
Combining querysets built on different models should behave in a well - defined
fashion . We raise an error .
>> > Author . objects . all ( ) & Tag . objects . all ( )
Traceback ( most recent call last ) :
. . .
AssertionError : Cannot combine queries on two different base models .
>> > Author . objects . all ( ) | Tag . objects . all ( )
Traceback ( most recent call last ) :
. . .
AssertionError : Cannot combine queries on two different base models .
Bug #3141
>> > Author . objects . extra ( select = { ' foo ' : ' 1 ' } ) . count ( )
4
>> > Author . objects . extra ( select = { ' foo ' : ' %s ' } , select_params = ( 1 , ) ) . count ( )
4
Bug #2400
>> > Author . objects . filter ( item__isnull = True )
[ < Author : a3 > ]
>> > Tag . objects . filter ( item__isnull = True )
[ < Tag : t5 > ]
Bug #2496
>> > Item . objects . extra ( tables = [ ' queries_author ' ] ) . select_related ( ) . order_by ( ' name ' ) [ : 1 ]
[ < Item : four > ]
Bug #2076
# Ordering on related tables should be possible, even if the table is not
# otherwise involved.
>> > Item . objects . order_by ( ' note__note ' , ' name ' )
[ < Item : two > , < Item : four > , < Item : one > , < Item : three > ]
# Ordering on a related field should use the remote model's default ordering as
# a final step.
>> > Author . objects . order_by ( ' extra ' , ' -name ' )
[ < Author : a2 > , < Author : a1 > , < Author : a4 > , < Author : a3 > ]
# Using remote model default ordering can span multiple models (in this case,
# Cover is ordered by Item's default, which uses Note's default).
>> > Cover . objects . all ( )
[ < Cover : first > , < Cover : second > ]
# If the remote model does not have a default ordering, we order by its 'id'
# field.
>> > Item . objects . order_by ( ' creator ' , ' name ' )
[ < Item : one > , < Item : three > , < Item : two > , < Item : four > ]
# Cross model ordering is possible in Meta, too.
>> > Ranking . objects . all ( )
[ < Ranking : 3 : a1 > , < Ranking : 2 : a2 > , < Ranking : 1 : a3 > ]
>> > Ranking . objects . all ( ) . order_by ( ' rank ' )
[ < Ranking : 1 : a3 > , < Ranking : 2 : a2 > , < Ranking : 3 : a1 > ]
# Ordering by a many-valued attribute (e.g. a many-to-many or reverse
# ForeignKey) is legal, but the results might not make sense. That isn't
# Django's problem. Garbage in, garbage out.
2008-06-26 14:50:22 +08:00
>> > Item . objects . filter ( tags__isnull = False ) . order_by ( ' tags ' , ' id ' )
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
[ < Item : one > , < Item : two > , < Item : one > , < Item : two > , < Item : four > ]
# If we replace the default ordering, Django adjusts the required tables
# automatically. Item normally requires a join with Note to do the default
# ordering, but that isn't needed here.
>> > qs = Item . objects . order_by ( ' name ' )
2008-10-08 16:38:33 +08:00
>> > list ( qs )
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
[ < Item : four > , < Item : one > , < Item : three > , < Item : two > ]
>> > len ( qs . query . tables )
1
# Ordering of extra() pieces is possible, too and you can mix extra fields and
# model fields in the ordering.
>> > Ranking . objects . extra ( tables = [ ' django_site ' ] , order_by = [ ' -django_site.id ' , ' rank ' ] )
[ < Ranking : 1 : a3 > , < Ranking : 2 : a2 > , < Ranking : 3 : a1 > ]
>> > qs = Ranking . objects . extra ( select = { ' good ' : ' case when rank > 2 then 1 else 0 end ' } )
>> > [ o . good for o in qs . extra ( order_by = ( ' -good ' , ) ) ] == [ True , False , False ]
True
>> > qs . extra ( order_by = ( ' -good ' , ' id ' ) )
[ < Ranking : 3 : a1 > , < Ranking : 2 : a2 > , < Ranking : 1 : a3 > ]
# Despite having some extra aliases in the query, we can still omit them in a
# values() query.
2008-06-06 19:47:47 +08:00
>> > dicts = qs . values ( ' id ' , ' rank ' ) . order_by ( ' id ' )
>> > [ sorted ( d . items ( ) ) for d in dicts ]
[ [ ( ' id ' , 1 ) , ( ' rank ' , 2 ) ] , [ ( ' id ' , 2 ) , ( ' rank ' , 1 ) ] , [ ( ' id ' , 3 ) , ( ' rank ' , 3 ) ] ]
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
2008-06-15 14:24:41 +08:00
Bug #7256
# An empty values() call includes all aliases, including those from an extra()
>> > dicts = qs . values ( ) . order_by ( ' id ' )
>> > [ sorted ( d . items ( ) ) for d in dicts ]
[ [ ( ' 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 ) ] ]
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
Bugs #2874, #3002
>> > qs = Item . objects . select_related ( ) . order_by ( ' note__note ' , ' name ' )
>> > list ( qs )
[ < Item : two > , < Item : four > , < Item : one > , < Item : three > ]
# This is also a good select_related() test because there are multiple Note
# entries in the SQL. The two Note items should be different.
>> > qs [ 0 ] . note , qs [ 0 ] . creator . extra . note
( < Note : n2 > , < Note : n1 > )
Bug #3037
>> > Item . objects . filter ( Q ( creator__name = ' a3 ' , name = ' two ' ) | Q ( creator__name = ' a4 ' , name = ' four ' ) )
[ < Item : four > ]
Bug #5321, #7070
Ordering columns must be included in the output columns . Note that this means
results that might otherwise be distinct are not ( if there are multiple values
in the ordering cols ) , as in this example . This isn ' t a bug; it ' s a warning to
be careful with the selection of ordering columns .
>> > Note . objects . values ( ' misc ' ) . distinct ( ) . order_by ( ' note ' , ' -misc ' )
[ { ' misc ' : u ' foo ' } , { ' misc ' : u ' bar ' } , { ' misc ' : u ' foo ' } ]
Bug #4358
If you don ' t pass any fields to values(), relation fields are returned as
" foo_id " keys , not " foo " . For consistency , you should be able to pass " foo_id "
in the fields list and have it work , too . We actually allow both " foo " and
" foo_id " .
# The *_id version is returned by default.
>> > ' note_id ' in ExtraInfo . objects . values ( ) [ 0 ]
True
# You can also pass it in explicitly.
>> > ExtraInfo . objects . values ( ' note_id ' )
[ { ' note_id ' : 1 } , { ' note_id ' : 2 } ]
# ...or use the field name.
>> > ExtraInfo . objects . values ( ' note ' )
[ { ' note ' : 1 } , { ' note ' : 2 } ]
Bug #5261
>> > Note . objects . exclude ( Q ( ) )
[ < Note : n1 > , < Note : n2 > , < Note : n3 > ]
Bug #3045, #3288
Once upon a time , select_related ( ) with circular relations would loop
infinitely if you forgot to specify " depth " . Now we set an arbitrary default
upper bound .
>> > X . objects . all ( )
[ ]
>> > X . objects . select_related ( )
[ ]
Bug #3739
The all ( ) method on querysets returns a copy of the queryset .
>> > q1 = Item . objects . order_by ( ' name ' )
>> > id ( q1 ) == id ( q1 . all ( ) )
False
Bug #2902
Parameters can be given to extra_select , * if * you use a SortedDict .
( First we need to know which order the keys fall in " naturally " on your system ,
so we can put things in the wrong way around from normal . A normal dict would
thus fail . )
>> > from django . utils . datastructures import SortedDict
>> > s = [ ( ' a ' , ' %s ' ) , ( ' b ' , ' %s ' ) ]
>> > params = [ ' one ' , ' two ' ]
>> > if { ' a ' : 1 , ' b ' : 2 } . keys ( ) == [ ' a ' , ' b ' ] :
. . . s . reverse ( )
. . . params . reverse ( )
2008-12-08 10:39:51 +08:00
# This slightly odd comparison works around the fact that PostgreSQL will
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
# return 'one' and 'two' as strings, not Unicode objects. It's a side-effect of
# using constants here and not a real concern.
>> > d = Item . objects . extra ( select = SortedDict ( s ) , select_params = params ) . values ( ' a ' , ' b ' ) [ 0 ]
>> > d == { ' a ' : u ' one ' , ' b ' : u ' two ' }
True
# Order by the number of tags attached to an item.
>> > l = Item . objects . extra ( select = { ' count ' : ' select count(*) from queries_item_tags where queries_item_tags.item_id = queries_item.id ' } ) . order_by ( ' -count ' )
>> > [ o . count for o in l ]
[ 2 , 2 , 1 , 0 ]
Bug #6154
Multiple filter statements are joined using " AND " all the time .
>> > Author . objects . filter ( id = a1 . id ) . filter ( Q ( extra__note = n1 ) | Q ( item__note = n3 ) )
[ < Author : a1 > ]
>> > Author . objects . filter ( Q ( extra__note = n1 ) | Q ( item__note = n3 ) ) . filter ( id = a1 . id )
[ < Author : a1 > ]
Bug #6981
>> > Tag . objects . select_related ( ' parent ' ) . order_by ( ' name ' )
[ < Tag : t1 > , < Tag : t2 > , < Tag : t3 > , < Tag : t4 > , < Tag : t5 > ]
Bug #6180, #6203 -- dates with limits and/or counts
>> > Item . objects . count ( )
4
>> > Item . objects . dates ( ' created ' , ' month ' ) . count ( )
1
>> > Item . objects . dates ( ' created ' , ' day ' ) . count ( )
2
>> > len ( Item . objects . dates ( ' created ' , ' day ' ) )
2
>> > Item . objects . dates ( ' created ' , ' day ' ) [ 0 ]
datetime . datetime ( 2007 , 12 , 19 , 0 , 0 )
Bug #7087 -- dates with extra select columns
>> > Item . objects . dates ( ' created ' , ' day ' ) . extra ( select = { ' a ' : 1 } )
[ datetime . datetime ( 2007 , 12 , 19 , 0 , 0 ) , datetime . datetime ( 2007 , 12 , 20 , 0 , 0 ) ]
2008-06-25 21:38:06 +08:00
Bug #7155 -- nullable dates
>> > Item . objects . dates ( ' modified ' , ' day ' )
[ datetime . datetime ( 2007 , 12 , 19 , 0 , 0 ) ]
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
Test that parallel iterators work .
>> > qs = Tag . objects . all ( )
>> > i1 , i2 = iter ( qs ) , iter ( qs )
>> > i1 . next ( ) , i1 . next ( )
( < Tag : t1 > , < Tag : t2 > )
>> > i2 . next ( ) , i2 . next ( ) , i2 . next ( )
( < Tag : t1 > , < Tag : t2 > , < Tag : t3 > )
>> > i1 . next ( )
< Tag : t3 >
>> > qs = X . objects . all ( )
>> > bool ( qs )
False
>> > bool ( qs )
False
We can do slicing beyond what is currently in the result cache , too .
## FIXME!! This next test causes really weird PostgreSQL behaviour, but it's
## only apparent much later when the full test suite runs. I don't understand
## what's going on here yet.
##
2008-12-08 10:39:51 +08:00
## # We need to mess with the implementation internals a bit here to decrease the
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
## # cache fill size so that we don't read all the results at once.
## >>> from django.db.models import query
## >>> query.ITER_CHUNK_SIZE = 2
## >>> qs = Tag.objects.all()
##
## # Fill the cache with the first chunk.
## >>> bool(qs)
## True
## >>> len(qs._result_cache)
## 2
##
## # Query beyond the end of the cache and check that it is filled out as required.
## >>> qs[4]
## <Tag: t5>
## >>> len(qs._result_cache)
## 5
##
## # But querying beyond the end of the result set will fail.
## >>> qs[100]
## Traceback (most recent call last):
## ...
## IndexError: ...
Bug #7045 -- extra tables used to crash SQL construction on the second use.
>> > qs = Ranking . objects . extra ( tables = [ ' django_site ' ] )
>> > s = qs . query . as_sql ( )
>> > s = qs . query . as_sql ( ) # test passes if this doesn't raise an exception.
2008-04-28 10:27:19 +08:00
Bug #7098 -- Make sure semi-deprecated ordering by related models syntax still
works .
>> > Item . objects . values ( ' note__note ' ) . order_by ( ' queries_note.note ' , ' id ' )
[ { ' note__note ' : u ' n2 ' } , { ' note__note ' : u ' n3 ' } , { ' note__note ' : u ' n3 ' } , { ' note__note ' : u ' n3 ' } ]
2008-04-28 12:29:06 +08:00
Bug #7096 -- Make sure exclude() with multiple conditions continues to work.
>> > Tag . objects . filter ( parent = t1 , name = ' t3 ' ) . order_by ( ' name ' )
[ < Tag : t3 > ]
>> > Tag . objects . exclude ( parent = t1 , name = ' t3 ' ) . order_by ( ' name ' )
[ < Tag : t1 > , < Tag : t2 > , < Tag : t4 > , < Tag : t5 > ]
>> > Item . objects . exclude ( tags__name = ' t1 ' , name = ' one ' ) . order_by ( ' name ' ) . distinct ( )
[ < Item : four > , < Item : three > , < Item : two > ]
>> > Item . objects . filter ( name__in = [ ' three ' , ' four ' ] ) . exclude ( tags__name = ' t1 ' ) . order_by ( ' name ' )
[ < Item : four > , < Item : three > ]
More twisted cases , involving nested negations .
>> > Item . objects . exclude ( ~ Q ( tags__name = ' t1 ' , name = ' one ' ) )
[ < Item : one > ]
>> > Item . objects . filter ( ~ Q ( tags__name = ' t1 ' , name = ' one ' ) , name = ' two ' )
[ < Item : two > ]
>> > Item . objects . exclude ( ~ Q ( tags__name = ' t1 ' , name = ' one ' ) , name = ' two ' )
[ < Item : four > , < Item : one > , < Item : three > ]
2008-04-28 19:51:16 +08:00
Bug #7095
2008-12-08 10:39:51 +08:00
Updates that are filtered on the model being updated are somewhat tricky
2008-04-28 19:51:16 +08:00
in MySQL . This exercises that case .
2008-06-26 11:11:32 +08:00
>> > mm = ManagedModel . objects . create ( data = ' mm1 ' , tag = t1 , public = True )
2008-04-28 19:51:16 +08:00
>> > ManagedModel . objects . update ( data = ' mm ' )
2008-08-10 01:19:44 +08:00
1
2008-04-28 19:51:16 +08:00
2008-06-26 09:01:21 +08:00
A values ( ) or values_list ( ) query across joined models must use outer joins
appropriately .
>> > Report . objects . values_list ( " creator__extra__info " , flat = True ) . order_by ( " name " )
[ u ' e1 ' , u ' e2 ' , None ]
2008-06-26 09:02:11 +08:00
Similarly for select_related ( ) , joins beyond an initial nullable join must
use outer joins so that all results are included .
>> > Report . objects . select_related ( " creator " , " creator__extra " ) . order_by ( " name " )
[ < Report : r1 > , < Report : r2 > , < Report : r3 > ]
When there are multiple paths to a table from another table , we have to be
careful not to accidentally reuse an inappropriate join when using
select_related ( ) . We used to return the parent ' s Detail record here by mistake.
>> > d1 = Detail . objects . create ( data = " d1 " )
>> > d2 = Detail . objects . create ( data = " d2 " )
>> > m1 = Member . objects . create ( name = " m1 " , details = d1 )
>> > m2 = Member . objects . create ( name = " m2 " , details = d2 )
>> > c1 = Child . objects . create ( person = m2 , parent = m1 )
>> > obj = m1 . children . select_related ( " person__details " ) [ 0 ]
>> > obj . person . details . data
u ' d2 '
2008-06-26 13:34:26 +08:00
Bug #7076 -- excluding shouldn't eliminate NULL entries.
>> > Item . objects . exclude ( modified = time1 ) . order_by ( ' name ' )
[ < Item : four > , < Item : three > , < Item : two > ]
>> > Tag . objects . exclude ( parent__name = t1 . name )
[ < Tag : t1 > , < Tag : t4 > , < Tag : t5 > ]
2008-06-26 14:50:22 +08:00
Bug #7181 -- ordering by related tables should accomodate nullable fields (this
test is a little tricky , since NULL ordering is database dependent . Instead , we
just count the number of results ) .
>> > len ( Tag . objects . order_by ( ' parent__name ' ) )
5
2008-06-26 18:50:25 +08:00
Bug #7107 -- this shouldn't create an infinite loop.
>> > Valid . objects . all ( )
[ ]
2008-06-26 19:42:12 +08:00
Empty querysets can be merged with others .
>> > Note . objects . none ( ) | Note . objects . all ( )
[ < Note : n1 > , < Note : n2 > , < Note : n3 > ]
>> > Note . objects . all ( ) | Note . objects . none ( )
[ < Note : n1 > , < Note : n2 > , < Note : n3 > ]
>> > Note . objects . none ( ) & Note . objects . all ( )
[ ]
>> > Note . objects . all ( ) & Note . objects . none ( )
[ ]
2008-06-27 11:27:20 +08:00
Bug #7204, #7506 -- make sure querysets with related fields can be pickled. If
this doesn ' t crash, it ' s a Good Thing .
>> > out = pickle . dumps ( Item . objects . all ( ) )
2008-07-22 16:23:20 +08:00
We should also be able to pickle things that use select_related ( ) . The only
tricky thing here is to ensure that we do the related selections properly after
unpickling .
>> > qs = Item . objects . select_related ( )
>> > query = qs . query . as_sql ( ) [ 0 ]
>> > query2 = pickle . loads ( pickle . dumps ( qs . query ) )
>> > query2 . as_sql ( ) [ 0 ] == query
True
2009-03-19 17:06:04 +08:00
Check pickling of deferred - loading querysets
>> > qs = Item . objects . defer ( ' name ' , ' creator ' )
>> > q2 = pickle . loads ( pickle . dumps ( qs ) )
>> > list ( qs ) == list ( q2 )
True
2009-03-20 09:37:11 +08:00
>> > q3 = pickle . loads ( pickle . dumps ( qs , pickle . HIGHEST_PROTOCOL ) )
>> > list ( qs ) == list ( q3 )
True
2009-03-19 17:06:04 +08:00
2008-06-29 11:01:46 +08:00
Bug #7277
>> > n1 . annotation_set . filter ( Q ( tag = t5 ) | Q ( tag__children = t5 ) | Q ( tag__children__children = t5 ) )
[ < Annotation : a1 > ]
2008-06-29 19:15:48 +08:00
Bug #7371
>> > Related . objects . order_by ( ' custom ' )
[ ]
2008-07-11 17:00:35 +08:00
Bug #7448, #7707 -- Complex objects should be converted to strings before being
used in lookups .
>> > Item . objects . filter ( created__in = [ time1 , time2 ] )
[ < Item : one > , < Item : two > ]
2009-03-01 09:24:03 +08:00
Bug #7698, #10202 -- People like to slice with '0' as the high-water mark.
2008-07-11 20:43:27 +08:00
>> > Item . objects . all ( ) [ 0 : 0 ]
[ ]
2008-10-08 16:37:35 +08:00
>> > Item . objects . all ( ) [ 0 : 0 ] [ : 10 ]
[ ]
2009-03-01 09:24:03 +08:00
>> > Item . objects . all ( ) [ : 0 ] . count ( )
0
>> > Item . objects . all ( ) [ : 0 ] . latest ( ' created ' )
Traceback ( most recent call last ) :
. . .
AssertionError : Cannot change a query once a slice has been taken .
2008-07-11 20:43:27 +08:00
2008-07-16 02:47:32 +08:00
Bug #7411 - saving to db must work even with partially read result set in
another cursor .
>> > for num in range ( 2 * ITER_CHUNK_SIZE + 1 ) :
. . . _ = Number . objects . create ( num = num )
>> > for i , obj in enumerate ( Number . objects . all ( ) ) :
. . . obj . save ( )
. . . if i > 10 : break
2008-07-17 07:17:29 +08:00
Bug #7759 -- count should work with a partially read result set.
>> > count = Number . objects . count ( )
>> > qs = Number . objects . all ( )
>> > for obj in qs :
. . . qs . count ( ) == count
. . . break
True
2008-07-22 15:37:09 +08:00
Bug #7791 -- there were "issues" when ordering and distinct-ing on fields
related via ForeignKeys .
2008-07-23 02:56:50 +08:00
>> > len ( Note . objects . order_by ( ' extrainfo__info ' ) . distinct ( ) )
3
2008-07-22 15:37:09 +08:00
2008-07-27 12:18:52 +08:00
Bug #7778 - Model subclasses could not be deleted if a nullable foreign key
relates to a model that relates back .
>> > num_celebs = Celebrity . objects . count ( )
>> > tvc = TvChef . objects . create ( name = " Huey " )
>> > Celebrity . objects . count ( ) == num_celebs + 1
True
>> > f1 = Fan . objects . create ( fan_of = tvc )
>> > f2 = Fan . objects . create ( fan_of = tvc )
>> > tvc . delete ( )
# The parent object should have been deleted as well.
>> > Celebrity . objects . count ( ) == num_celebs
True
2008-08-17 04:40:00 +08:00
Bug #8283 -- Checking that applying filters after a disjunction works correctly.
>> > ( ExtraInfo . objects . filter ( note = n1 ) | ExtraInfo . objects . filter ( info = ' e2 ' ) ) . filter ( note = n1 )
[ < ExtraInfo : e1 > ]
>> > ( ExtraInfo . objects . filter ( info = ' e2 ' ) | ExtraInfo . objects . filter ( note = n1 ) ) . filter ( note = n1 )
[ < ExtraInfo : e1 > ]
2008-08-21 06:38:15 +08:00
Pickling of DateQuerySets used to fail
>> > qs = Item . objects . dates ( ' created ' , ' month ' )
>> > _ = pickle . loads ( pickle . dumps ( qs ) )
2008-08-30 06:29:38 +08:00
Bug #8683 -- raise proper error when a DateQuerySet gets passed a wrong type of field
>> > Item . objects . dates ( ' name ' , ' month ' )
Traceback ( most recent call last ) :
. . .
AssertionError : ' name ' isn ' t a DateField.
2008-08-28 13:42:05 +08:00
Bug #8597: regression tests for case-insensitive comparisons
>> > _ = Item . objects . create ( name = " a_b " , created = datetime . datetime . now ( ) , creator = a2 , note = n1 )
>> > _ = Item . objects . create ( name = " x % y " , created = datetime . datetime . now ( ) , creator = a2 , note = n1 )
>> > Item . objects . filter ( name__iexact = " A_b " )
[ < Item : a_b > ]
>> > Item . objects . filter ( name__iexact = " x % Y " )
[ < Item : x % y > ]
>> > Item . objects . filter ( name__istartswith = " A_b " )
[ < Item : a_b > ]
>> > Item . objects . filter ( name__iendswith = " A_b " )
[ < Item : a_b > ]
2008-09-01 20:07:26 +08:00
Bug #7302: reserved names are appropriately escaped
>> > _ = ReservedName . objects . create ( name = ' a ' , order = 42 )
>> > _ = ReservedName . objects . create ( name = ' b ' , order = 37 )
>> > ReservedName . objects . all ( ) . order_by ( ' order ' )
[ < ReservedName : b > , < ReservedName : a > ]
>> > ReservedName . objects . extra ( select = { ' stuff ' : ' name ' } , order_by = ( ' order ' , ' stuff ' ) )
[ < ReservedName : b > , < ReservedName : a > ]
2008-09-02 10:16:41 +08:00
Bug #8439 -- complex combinations of conjunctions, disjunctions and nullable
relations .
>> > Author . objects . filter ( Q ( item__note__extrainfo = e2 ) | Q ( report = r1 , name = ' xyz ' ) )
[ < Author : a2 > ]
>> > Author . objects . filter ( Q ( report = r1 , name = ' xyz ' ) | Q ( item__note__extrainfo = e2 ) )
[ < Author : a2 > ]
>> > Annotation . objects . filter ( Q ( tag__parent = t1 ) | Q ( notes__note = ' n1 ' , name = ' a1 ' ) )
[ < Annotation : a1 > ]
>> > xx = ExtraInfo . objects . create ( info = ' xx ' , note = n3 )
>> > Note . objects . filter ( Q ( extrainfo__author = a1 ) | Q ( extrainfo = xx ) )
[ < Note : n1 > , < Note : n3 > ]
>> > xx . delete ( )
>> > q = Note . objects . filter ( Q ( extrainfo__author = a1 ) | Q ( extrainfo = xx ) ) . query
>> > len ( [ x [ 2 ] for x in q . alias_map . values ( ) if x [ 2 ] == q . LOUTER and q . alias_refcount [ x [ 1 ] ] ] )
1
2008-10-24 14:24:04 +08:00
Make sure bump_prefix ( ) ( an internal Query method ) doesn ' t (re-)break. It ' s
sufficient that this query runs without error .
>> > qs = Tag . objects . values_list ( ' id ' , flat = True ) . order_by ( ' id ' )
>> > qs . query . bump_prefix ( )
>> > list ( qs )
[ 1 , 2 , 3 , 4 , 5 ]
2008-10-08 17:45:27 +08:00
Calling order_by ( ) with no parameters removes any existing ordering on the
model . But it should still be possible to add new ordering after that .
>> > qs = Author . objects . order_by ( ) . order_by ( ' name ' )
>> > ' ORDER BY ' in qs . query . as_sql ( ) [ 0 ]
True
2008-12-07 13:48:01 +08:00
2008-12-08 10:39:51 +08:00
Incorrect SQL was being generated for certain types of exclude ( ) queries that
crossed multi - valued relations ( #8921, #9188 and some pre-emptively discovered
cases ) .
2008-12-07 13:48:01 +08:00
>> > PointerA . objects . filter ( connection__pointerb__id = 1 )
[ ]
>> > PointerA . objects . exclude ( connection__pointerb__id = 1 )
[ ]
2008-12-08 10:39:51 +08:00
>> > Tag . objects . exclude ( children = None )
[ < Tag : t1 > , < Tag : t3 > ]
# This example is tricky because the parent could be NULL, so only checking
# parents with annotations omits some results (tag t1, in this case).
>> > Tag . objects . exclude ( parent__annotation__name = " a1 " )
[ < Tag : t1 > , < Tag : t4 > , < Tag : t5 > ]
# The annotation->tag link is single values and tag->children links is
# multi-valued. So we have to split the exclude filter in the middle and then
# optimise the inner query without losing results.
>> > Annotation . objects . exclude ( tag__children__name = " t2 " )
[ < Annotation : a2 > ]
2009-01-05 19:47:48 +08:00
Nested queries are possible ( although should be used with care , since they have
performance problems on backends like MySQL .
>> > Annotation . objects . filter ( notes__in = Note . objects . filter ( note = " n1 " ) )
[ < Annotation : a1 > ]
2009-01-08 13:16:21 +08:00
Nested queries should not evaluate the inner query as part of constructing the
2009-03-02 14:08:02 +08:00
SQL ( so we should see a nested query here , indicated by two " SELECT " calls ) .
>> > Annotation . objects . filter ( notes__in = Note . objects . filter ( note = " xyzzy " ) ) . query . as_sql ( ) [ 0 ] . count ( ' SELECT ' )
2
Bug #10181 -- Avoid raising an EmptyResultSet if an inner query is provably
empty ( and hence , not executed ) .
>> > Tag . objects . filter ( id__in = Tag . objects . filter ( id__in = [ ] ) )
[ ]
2009-01-08 13:16:21 +08:00
2009-01-16 18:59:43 +08:00
Bug #9997 -- If a ValuesList or Values queryset is passed as an inner query, we
make sure it ' s only requesting a single value and use that as the thing to
select .
>> > Tag . objects . filter ( name__in = Tag . objects . filter ( parent = t1 ) . values ( ' name ' ) )
[ < Tag : t2 > , < Tag : t3 > ]
# Multi-valued values() and values_list() querysets should raise errors.
>> > Tag . objects . filter ( name__in = Tag . objects . filter ( parent = t1 ) . values ( ' name ' , ' id ' ) )
Traceback ( most recent call last ) :
. . .
TypeError : Cannot use a multi - field ValuesQuerySet as a filter value .
>> > Tag . objects . filter ( name__in = Tag . objects . filter ( parent = t1 ) . values_list ( ' name ' , ' id ' ) )
Traceback ( most recent call last ) :
. . .
TypeError : Cannot use a multi - field ValuesListQuerySet as a filter value .
2009-01-08 13:49:03 +08:00
Bug #9985 -- qs.values_list(...).values(...) combinations should work.
>> > Note . objects . values_list ( " note " , flat = True ) . values ( " id " ) . order_by ( " id " )
[ { ' id ' : 1 } , { ' id ' : 2 } , { ' id ' : 3 } ]
>> > Annotation . objects . filter ( notes__in = Note . objects . filter ( note = " n1 " ) . values_list ( ' note ' ) . values ( ' id ' ) )
[ < Annotation : a1 > ]
2009-02-28 10:59:40 +08:00
Bug #10028 -- ordering by model related to nullable relations(!) should use
outer joins , so that all results are included .
>> > _ = Plaything . objects . create ( name = " p1 " )
>> > Plaything . objects . all ( )
[ < Plaything : p1 > ]
2009-03-01 09:56:59 +08:00
Bug #10205 -- When bailing out early because of an empty "__in" filter, we need
to set things up correctly internally so that subqueries can continue properly .
>> > Tag . objects . filter ( name__in = ( ) ) . update ( name = " foo " )
0
2009-03-08 11:32:16 +08:00
Bug #10432 (see also the Python 2.4+ tests for this, below). Testing an empty
" __in " filter with a generator as the value .
>> > def f ( ) :
. . . return iter ( [ ] )
>> > n_obj = Note . objects . all ( ) [ 0 ]
>> > def g ( ) :
. . . for i in [ n_obj . pk ] :
. . . yield i
>> > Note . objects . filter ( pk__in = f ( ) )
[ ]
>> > list ( Note . objects . filter ( pk__in = g ( ) ) ) == [ n_obj ]
True
Merged the queryset-refactor branch into trunk.
This is a big internal change, but mostly backwards compatible with existing
code. Also adds a couple of new features.
Fixed #245, #1050, #1656, #1801, #2076, #2091, #2150, #2253, #2306, #2400, #2430, #2482, #2496, #2676, #2737, #2874, #2902, #2939, #3037, #3141, #3288, #3440, #3592, #3739, #4088, #4260, #4289, #4306, #4358, #4464, #4510, #4858, #5012, #5020, #5261, #5295, #5321, #5324, #5325, #5555, #5707, #5796, #5817, #5987, #6018, #6074, #6088, #6154, #6177, #6180, #6203, #6658
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7477 bcc190cf-cafb-0310-a4f2-bffc1f526a37
2008-04-27 10:50:16 +08:00
""" }
2008-08-26 11:22:44 +08:00
# In Python 2.3 and the Python 2.6 beta releases, exceptions raised in __len__
# are swallowed (Python issue 1242657), so these cases return an empty list,
# rather than raising an exception. Not a lot we can do about that,
# unfortunately, due to the way Python handles list() calls internally. Thus,
# we skip the tests for Python 2.3 and 2.6.
if ( 2 , 4 ) < = sys . version_info < ( 2 , 6 ) :
2008-07-17 07:55:10 +08:00
__test__ [ " API_TESTS " ] + = """
# If you're not careful, it's possible to introduce infinite loops via default
# ordering on foreign keys in a cycle. We detect that.
>> > LoopX . objects . all ( )
Traceback ( most recent call last ) :
. . .
FieldError : Infinite loop caused by ordering .
>> > LoopZ . objects . all ( )
Traceback ( most recent call last ) :
. . .
FieldError : Infinite loop caused by ordering .
2008-08-12 07:40:34 +08:00
# Note that this doesn't cause an infinite loop, since the default ordering on
# the Tag model is empty (and thus defaults to using "id" for the related
# field).
>> > len ( Tag . objects . order_by ( ' parent ' ) )
5
2008-07-17 07:55:10 +08:00
# ... but you can still order in a non-recursive fashion amongst linked fields
# (the previous test failed because the default ordering was recursive).
>> > LoopX . objects . all ( ) . order_by ( ' y__x__y__x__id ' )
[ ]
2008-08-12 07:40:34 +08:00
2008-07-17 07:55:10 +08:00
"""
2008-12-10 13:19:27 +08:00
if settings . DATABASE_ENGINE == " mysql " :
__test__ [ " API_TESTS " ] + = """
When grouping without specifying ordering , we add an explicit " ORDER BY NULL "
portion in MySQL to prevent unnecessary sorting .
>> > query = Tag . objects . values_list ( ' parent_id ' , flat = True ) . order_by ( ) . query
>> > query . group_by = [ ' parent_id ' ]
>> > sql = query . as_sql ( ) [ 0 ]
>> > fragment = " ORDER BY "
>> > pos = sql . find ( fragment )
>> > sql . find ( fragment , pos + 1 ) == - 1
True
>> > sql . find ( " NULL " , pos + len ( fragment ) ) == pos + len ( fragment )
True
"""
2009-03-08 11:32:16 +08:00
# Generator expressions are only in Python 2.4 and later.
if sys . version_info > = ( 2 , 4 ) :
__test__ [ " API_TESTS " ] + = """
Using an empty generator expression as the rvalue for an " __in " lookup is legal
( regression for #10432).
>> > Note . objects . filter ( pk__in = ( x for x in ( ) ) )
[ ]
"""