views:

257

answers:

2

Hi,

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.

A: 

I think this should work:

class Membership(models.Model):
    ...

    class Meta:
        ordering = ['date_joined']
SmileyChris
Unfotunately it doesn't, the ManyRelatedManager seems to copy the ordering of target model :(
pielgrzym
That seems dumb, doesn't it. I suggest opening a ticket and bring this up in the django-dev google group
SmileyChris
Good idea, I'll do that and post back here what emerged of the discussion :)
pielgrzym
+2  A: 

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.

pielgrzym