﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
27536	order_by('pk') is not obeyed if superclass has default ordering	Andrew Dodd	nobody	"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=200)
    extra = models.CharField(max_length=200)


class SuperWithOrdering(models.Model):
    name = models.CharField(max_length=200)
    extra = models.CharField(max_length=200)

    class Meta:
        ordering = ('name', 'extra')


class SubFromSuperWithoutOrdering(SuperWithoutOrdering):
    anything = models.CharField(max_length=200)


class SubFromSuperWithOrdering(SuperWithOrdering):
    anything = models.CharField(max_length=200)

    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'."	Bug	new	Database layer (models, ORM)	1.10	Normal		order_by ordering		Unreviewed	0	0	0	0	0	0
