Opened 5 years ago

Last modified 3 years ago

#30460 new New feature

ManyToMany relationships with a custom `through` do not respect Meta.ordering on the intermediary model

Reported by: Ryan Petrello Owned by: nobody
Component: Database layer (models, ORM) Version: dev
Severity: Normal Keywords:
Cc: Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: yes
Easy pickings: no UI/UX: no


ManyToManyFields that specify an intermediary model with a custom Meta.ordering do not inherit that ordering.

class Dog(models.Model):

class OrderedMembership(models.Model):

    class Meta:
        ordering = ('position',)

    dog = models.ForeignKey('Dog', models.CASCADE)
    winner = models.ForeignKey('Winner', models.CASCADE)
    position = models.PositiveIntegerField()

class Winner(models.Model):
    name = models.CharField(max_length=128)
    # OrderedMembership object defined as a class
    members = models.ManyToManyField(Dog, through=OrderedMembership)

lassie = Dog('Lassie')
fido = Dog('Fido')
rover = Dog('Rover')
dog_show = Winner(name='Dog Show')
OrderedMembership.objects.create(dog=lassie, winner=dog_show, position=3)
OrderedMembership.objects.create(dog=fido, winner=dog_show, position=2)
OrderedMembership.objects.create(dog=rover, winner=dog_show, position=1)

dog_show.members.all()   # <--- does not respect `OrderedMembership.position`

This means that if you want to create a custom M2M model that manages default order via some column on the M2M table: doesn't work as you'd expect (the M2M relation falls back to natural database order - usually the primary key of the target model).

Change History (4)

comment:1 by Simon Charette, 5 years ago

Has patch: set
Patch needs improvement: set
Triage Stage: UnreviewedAccepted
Type: BugNew feature

I wouldn't say this is actually a bug as many-to-many field managers have always supported ordering on their referenced model

Adding support for through._meta.ordering has backward compatibility concerns as we have to decide how to deal with ordering defined on both the through and to model. Should the through ordering have precedence over the toordering? Should they be merged together? We also have to make sure whatever we do regarding ordering translation honors the mechanisms in place to exclude Meta.ordering from aggregation as naively translating it into an order_by call will bypass the checks added in 1b1f64ee5a78cc217fead52cbae23114502cf564 for #14357.

In my opinion the resulting ordering should be through._meta.ordering + to._meta.ordering. This might require a django-developers thread to gather feedback though.

Accepting the ticket on the basis that it seems like a feature that should be supported but the current PR requires significant adjustments first.

comment:2 by Asif Saifuddin Auvi, 4 years ago

Version: 2.2master

comment:3 by Baptiste Mispelon, 4 years ago

I just closed #17344 as a duplicate. It was older but there wasn't much discussion on that ticket so I figured I would keep this one open instead.

I'll also note that there's #17345 which is partially related (being able to define an explicit ordering without using a through table).

comment:4 by Maarten Nieber, 3 years ago

I just found out that you can use dog_show.members.all().order_by('orderedmembership'). However, afaik, this (surprising!) feature is not documented, would be nice to add this to the docs.

Note: See TracTickets for help on using tickets.
Back to Top