Getting to the middle of things

The cause

I've been using Django Polymorphic quite a lot lately, and to great effect. However, there are some limitations.

Recently, as I was trying to reduce the number of queries on a complex site, I found one part of the code was quite messy, and causing a lot of extra queries, as it used a M2M relation with a 'through' table to a Polymorphic class, then tried to use the extra data on the through.

What's worse, it only needed one field from the 'through' table.

Imagine we have the following models (thanks to Y3Klo for the easy example):

class Item(models.Model):
    ...

class Box(models.Model):
    items = models.ManyToManyField(items, through='BoxItem')

class BoxItem(models.Model):
    box = models.ForeignKey('Box')
    item = models.ForeignKey('Item')
    quantity = models.IntegerField(default=0)

Here's an example of what the code was left doing:

for boxitem in box.boxitem_set.all():
    print boxitem.item.title, boxitem.quantity

Now, that doesn't look so bad, does it? However, in my case my 'Item' was using PolymorphicModel ... but selecting it like this didn't yield the child-class, only the base-class.

A select solution

Fortunately, there's a clean and efficient solution!

for item in box.items.extra(select={'quantity': 'myapp_boxitem.quantity'}):
    print item.title, item.quantity

Now, I can 'naturally' iterate over the m2m relation, and still get my through table attribute. Since in the SQL the table is involved for the m2m join, the fields are available to select without any extra cost!

comments powered by Disqus