views:

508

answers:

1

Django documents give this example of associating extra data with a M2M relationship. Although that is straight forward, now that I am trying to make use of the extra data in my views it is feeling very clumsy (which typically means "I'm doing it wrong").

For example, using the models defined in the linked document above I can do the following:

# Some people
ringo = Person.objects.create(name="Ringo Starr")
paul = Person.objects.create(name="Paul McCartney")
me = Person.objects.create(name="Me the rock Star")
# Some bands
beatles = Group.objects.create(name="The Beatles")
my_band = Group.objects.create(name="My Imaginary band")
# The Beatles form
m1 = Membership.objects.create(person=ringo, group=beatles,
    date_joined=date(1962, 8, 16),
    invite_reason= "Needed a new drummer.")
m2 = Membership.objects.create(person=paul, group=beatles,
    date_joined=date(1960, 8, 1),
    invite_reason= "Wanted to form a band.")
# My Imaginary band forms
m3 = Membership.objects.create(person=me, group=my_band,
    date_joined=date(1980, 10, 5),
    invite_reason= "Want to be a star.")
m4 = Membership.objects.create(person=paul, group=my_band,
    date_joined=date(1980, 10, 5),
    invite_reason= "Wanted to form a better band.")

Now if I want to print a simple table that for each person gives the date that they joined each band, at the moment I am doing this:

bands =  Group.objects.all().order_by('name')

for person in Person.objects.all():
    print person.name, 
    for band in bands:
        print band.name,
        try:
            m = person.membership_set.get(group=band.pk)
            print m.date_joined,
        except:
            print 'NA',
    print ""

Which feels very ugly, especially the "m = person.membership_set.get(group=band.pk)" bit. Am I going about this whole thing wrong?

Now say I wanted to order the people by the date that they joined a particular band (say the beatles) is there any order_by clause I can put on Person.objects.all() that would let me do that?

Any advice would be greatly appreciated.

+1  A: 

You should query the Membership model instead:

members = Membership.objects.select_related('person', 'group').all().order_by('date_joined')

for m in members:
    print m.band.name, m.person.name, m.date_joined

Using select_related here we avoid the 1 + n queries problem, as it tells the ORM to do the join and selects everything in one single query.

Tiago
Thanks for your answer. It of course answers the question I asked, but on reflection I realized I asked the wrong question. I had another attempt at explaining the problem space [here][1]. Cheers. [1]: http://stackoverflow.com/questions/1291889/is-a-many-to-many-relationship-with-extra-fields-the-right-tool-for-my-job
whichhand
Lesson #2: comments don't accept markup.
whichhand