Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Default ordering for m2m items by intermediate model field in Django

I have an unusual problem. Let's consider such models (taken from django docs):

class Person(models.Model):
    name = models.CharField(max_length=128)

    def __unicode__(self):
        return self.name

class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField(Person, through='Membership')

    def __unicode__(self):
        return self.name

class Membership(models.Model):
    person = models.ForeignKey(Person)
    group = models.ForeignKey(Group)
    date_joined = models.DateField()
    invite_reason = models.CharField(max_length=64)

Now, let's say we've got 2 Beatles members in out Beatles band (following the example in django docs for intermediate models):

>>> beatles.members.all()
[<Person: Ringo Starr>, <Person: Paul McCartney>]

The above code will return members sorted by default ordering for Person model. If I specify:

>>> beatles.members.all().order_by('membership__date_joined') 

the members, are sorted via the date joined. Can I somehow set this as default behavior for this ManyToMany field? That is to set default order of related items by field in the intermediate model? The ManyRelatedManager seems to have an init argument core_filters, but I have no vague idea how to access it withous subclassing the whole m2m field in django. Any creative ideas? :)

Thanks in advance :)

I've opened a ticket in django trac.

like image 417
pielgrzym Avatar asked Sep 07 '09 18:09

pielgrzym


1 Answers

Here is a dirty-hack method to achieve this (look at Group model):

class Person(models.Model):
    name = models.CharField(max_length=128)

    def __unicode__(self):
        return self.name

class Group(models.Model):
    name = models.CharField(max_length=128)
    _members = models.ManyToManyField(Person, through='Membership')
    @property
    def members(self):
        return self._members.order_by('membership__date_joined')

    def __unicode__(self):
        return self.name

class Membership(models.Model):
    person = models.ForeignKey(Person)
    group = models.ForeignKey(Group)
    date_joined = models.DateField()
    invite_reason = models.CharField(max_length=64)

Didn't bother to create a set property decorator, but it should be quite easy to mimic the setting of original field. Ugly workaround, but seems to do the trick.

like image 198
pielgrzym Avatar answered Sep 16 '22 15:09

pielgrzym