queryset order_by method added, testcase, docs

This commit is contained in:
Bert Constantin
2010-02-02 17:29:31 +01:00
parent b4aeae417e
commit 2fcb7fba1a
3 changed files with 71 additions and 26 deletions
+15 -3
View File
@@ -105,6 +105,11 @@ class PolymorphicQuerySet(QuerySet):
additional_args = _translate_polymorphic_filter_definitions_in_kwargs(self.model, kwargs) # filter_field='data'
return super(PolymorphicQuerySet, self)._filter_or_exclude(negate, *(list(args) + additional_args), **kwargs)
def order_by(self, *args, **kwargs):
"""translate the field paths in the args, then call vanilla order_by."""
new_args = [ _translate_polymorphic_field_path(self.model, a) for a in args ]
return super(PolymorphicQuerySet, self).order_by(*new_args, **kwargs)
def _process_aggregate_args(self, args, kwargs):
"""for aggregate and annotate kwargs: allow ModelX___field syntax for kwargs, forbid it for args.
Modifies kwargs if needed (these are Aggregate objects, we translate the lookup member variable)"""
@@ -125,7 +130,7 @@ class PolymorphicQuerySet(QuerySet):
self._process_aggregate_args(args, kwargs)
self.polymorphic_disabled = True
return super(PolymorphicQuerySet, self).aggregate(*args, **kwargs)
def extra(self, *args, **kwargs):
self.polymorphic_disabled = not kwargs.get('polymorphic',False)
if 'polymorphic' in kwargs: kwargs.pop('polymorphic')
@@ -345,12 +350,19 @@ def _translate_polymorphic_field_path(queryset_model, field_path):
"""
Translate a field path from a keyword argument, as used for
PolymorphicQuerySet.filter()-like functions (and Q objects).
Supports leading '-' (for order_by args).
E.g.: ModelC___field3 is translated into modela__modelb__modelc__field3
Returns: translated path
Returns: translated path (unchanged, if no translation needed)
"""
classname, sep, pure_field_path = field_path.partition('___')
if not sep: return field_path
assert classname, 'PolymorphicModel: %s: bad field specification' % field_path
negated = False
if classname[0] == '-':
negated = True
classname = classname.lstrip('-')
if '__' in classname:
# the user has app label prepended to class name via __ => use Django's get_model function
@@ -398,7 +410,7 @@ def _translate_polymorphic_field_path(queryset_model, field_path):
return ''
basepath = _create_base_path(queryset_model, model)
newpath = basepath + '__' if basepath else ''
newpath = ('-' if negated else '') + basepath + ('__' if basepath else '')
newpath += pure_field_path
return newpath
+38 -8
View File
@@ -92,7 +92,7 @@ class MgrInheritC(ShowFieldsAndTypes, MgrInheritB):
class BlogBase(ShowFieldsAndTypes, PolymorphicModel):
name = models.CharField(max_length=10)
class BlogA(BlogBase):
pass
info = models.CharField(max_length=10)
class BlogB(BlogBase):
pass
class BlogA_Entry(ShowFieldsAndTypes, PolymorphicModel):
@@ -119,25 +119,55 @@ class testclass(TestCase):
print 'DiamondXY fields 2: field_b "%s", field_x "%s", field_y "%s"' % (o.field_b, o.field_x, o.field_y)
if o.field_b != 'b': print '# Django model inheritance diamond problem detected'
def test_annotate_aggregate(self):
def test_annotate_aggregate_order(self):
from django.db.models import Count
BlogA.objects.all().delete()
blog = BlogA.objects.create(name='B1')
blog = BlogA.objects.create(name='B1', info='i1')
entry1 = blog.bloga_entry_set.create(text='bla')
entry2 = BlogA_Entry.objects.create(blog=blog, text='bla2')
# create some BlogB to make the table more diverse
o = BlogB.objects.create(name='Bb1')
o = BlogB.objects.create(name='Bb2')
o = BlogB.objects.create(name='Bb3')
qs = BlogBase.objects.annotate(entrycount=Count('BlogA___bloga_entry'))
assert qs[0].entrycount == 2
x = BlogBase.objects.aggregate(entrycount=Count('BlogA___bloga_entry'))
assert x['entrycount'] == 2
# create some more blogs for next test
b2 = BlogA.objects.create(name='B2', info='i2')
b2 = BlogA.objects.create(name='B3', info='i3')
b2 = BlogA.objects.create(name='B4', info='i4')
b2 = BlogA.objects.create(name='B5', info='i5')
# test ordering
expected = '''
[ <BlogB: id 4, name (CharField): "Bb3", >,
<BlogB: id 3, name (CharField): "Bb2", >,
<BlogB: id 2, name (CharField): "Bb1", >,
<BlogA: id 8, name (CharField): "B5", info (CharField): "i5">,
<BlogA: id 7, name (CharField): "B4", info (CharField): "i4">,
<BlogA: id 6, name (CharField): "B3", info (CharField): "i3">,
<BlogA: id 5, name (CharField): "B2", info (CharField): "i2">,
<BlogA: id 1, name (CharField): "B1", info (CharField): "i1"> ]'''
x = '\n' + repr(BlogBase.objects.order_by('-name'))
assert x == expected
def test_extra(self):
Model2A.objects.create(field1='A1')
Model2B.objects.create(field1='B1', field2='B2')
Model2C.objects.create(field1='C1', field2='C2', field3='C3')
expected='''
[ <BlogA: id 8, name (CharField): "B5", info (CharField): "i5">,
<BlogA: id 7, name (CharField): "B4", info (CharField): "i4">,
<BlogA: id 6, name (CharField): "B3", info (CharField): "i3">,
<BlogA: id 5, name (CharField): "B2", info (CharField): "i2">,
<BlogA: id 1, name (CharField): "B1", info (CharField): "i1">,
<BlogB: id 2, name (CharField): "Bb1", >,
<BlogB: id 3, name (CharField): "Bb2", >,
<BlogB: id 4, name (CharField): "Bb3", > ]'''
x = '\n' + repr(BlogBase.objects.order_by('-BlogA___info'))
assert x == expected
__test__ = {"doctest": """
#######################################################