#27536: order_by('pk') is not obeyed if superclass has default ordering
-------------------------------------+-------------------------------------
Reporter: Andrew | Owner: nobody
Dodd |
Type: Bug | Status: new
Component: Database | Version: 1.10
layer (models, ORM) |
Severity: Normal | Keywords: order_by ordering
Triage Stage: | Has patch: 0
Unreviewed |
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
-------------------------------------+-------------------------------------
Using 'pk' as an order_by() target does not work if the superclass has a
default ordering specified on its 'Meta' class.
For example, with the following classes:
{{{
#!python
class SuperWithoutOrdering(models.Model):
name = models.CharField(max_length=20)
extra = models.CharField(max_length=20)
class SuperWithOrdering(models.Model):
name = models.CharField(max_length=20)
extra = models.CharField(max_length=20)
class Meta:
ordering = ('name', 'extra')
class SubFromSuperWithoutOrdering(SuperWithoutOrdering):
anything = models.CharField(max_length=20)
class SubFromSuperWithOrdering(SuperWithOrdering):
anything = models.CharField(max_length=20)
def __str__(self):
# so test output is readable
return 'SubWithOrdering - name:{} extra:{} anything:{}'.format(
self.name, self.extra, self.anything)
}}}
Then:
{{{
#!python
SubFromSuperWithoutOrdering.objects.all().order_by('pk') # works, ordering
by id
SubFromSuperWithOrdering.object.all().order_by('pk') # does not work, it
just orders by 'name' then 'extra'
}}}
I have two tests that demonstrate this.
One that compares the 'ORDER BY' clause of the actual SQL queries:
{{{
#!python
class TestOrderByClause(TestCase):
def
test_it_orders_by_pk_and_id_are_the_same_if_super_does_not_have_ordering(self):
qs = SubFromSuperWithoutOrdering.objects.all()
by_pk = str(qs.order_by('pk').query).split('ORDER BY')[1]
by_id = str(qs.order_by('id').query).split('ORDER BY')[1]
self.assertEquals(by_pk, by_id) # PASSES
def
test_it_orders_by_pk_and_id_are_the_same_if_super_does_have_ordering(self):
qs = SubFromSuperWithOrdering.objects.all()
by_pk = str(qs.order_by('pk').query).split('ORDER BY')[1]
by_id = str(qs.order_by('id').query).split('ORDER BY')[1]
self.assertEquals(by_pk, by_id) # FAILS
# Alternative form?
def test_order_by_clause_is_the_same_if_using_pk_or_id(self):
for test_class in [SubFromSuperWithoutOrdering,
SubFromSuperWithOrdering]:
qs = test_class.objects.all()
by_pk = str(qs.order_by('pk').query).split('ORDER BY')[1]
by_id = str(qs.order_by('id').query).split('ORDER BY')[1]
self.assertEquals(by_pk, by_id, 'Failed for
{}'.format(test_class))
}}}
And one that compares the order of the items actually returned from
executing the query:
{{{
#!python
class TestOrderingOfQuerySetWhenSuperclassHasDefaultOrdering(TestCase):
def setUp(self):
def make_obj(name, extra, anything):
return SubFromSuperWithOrdering.objects.create(name=name,
extra=extra, anything=anything)
self.zoot2 = make_obj( 'Zoot', 'ZZZ - Unknown', 'fourth by
super ordering, first by pk')
self.zoot1 = make_obj( 'Zoot', 'AAA - Handmaiden', 'third by
super ordering, second by pk')
self.arthur2 = make_obj('Arthur', 'ZZZ - Imposter', 'second by
super ordering, third by pk')
self.arthur1 = make_obj('Arthur', 'AAA - The King', 'first by
super ordering, fourth by pk')
def test_it_uses_superclass_ordering_by_default(self):
expected = [self.arthur1, self.arthur2, self.zoot1, self.zoot2]
actual = list(SubFromSuperWithOrdering.objects.all())
self.assertEqual(expected, actual)
def test_it_correctly_orders_with_id(self):
expected = [self.zoot2, self.zoot1, self.arthur2, self.arthur1]
actual =
list(SubFromSuperWithOrdering.objects.all().order_by('id'))
self.assertEqual(expected, actual)
def test_it_correctly_orders_with_pk(self):
expected = [self.zoot2, self.zoot1, self.arthur2, self.arthur1]
actual =
list(SubFromSuperWithOrdering.objects.all().order_by('pk'))
self.assertEqual(expected, actual)
}}}
I'm not very sure where to go looking to fix this. The workaround is to
specify the name of the field used as the PK instead of using 'pk'.
--
Ticket URL: <https://code.djangoproject.com/ticket/27536>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
--
You received this message because you are subscribed to the Google Groups
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/django-updates/053.c1d73acfbe737b1f1e3f2c08f83e26b9%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.