#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.

Reply via email to