tags:

views:

275

answers:

1

I've been drooling over Django all day while coding up an internal website in record time, but now I'm noticing that something is very inefficient with my ForeignKeys in the model.

I have a model which has 6 ForeignKeys, which are basically lookup tables. When I query all objects and display them in a template, it's running about 10 queries per item. Here's some code, which ought to explain it better:

class Website(models.Model):
    domain_name = models.CharField(max_length=100)
    registrant = models.ForeignKey('Registrant')
    account = models.ForeignKey('Account')
    registrar = models.ForeignKey('Registrar')
    server = models.ForeignKey('Server', related_name='server')
    host = models.ForeignKey('Host')
    target_server = models.ForeignKey('Server', related_name='target')

class Registrant(models.Model):
    name = models.CharField(max_length=100)

...and 5 more simple tables. There are 155 Website records, and in the view I'm using:

Website.objects.all()

It ends up executing 1544 queries. In the template, I'm using all of the foreign fields, as in:

<span class="value">Registrant:</span> <a href="/filter/registrant/{{ website.registrant.id }}">{{ website.registrant.name }}</a><br />

So I know it's going to run a lot of queries...but it seems like this is excessive. Is this normal? Should I not be doing it this way?

I'm pretty new to Django, so hopefully I'm just doing something stupid. It's definitely a pretty amazing framework.

+2  A: 

You should use the select_related function, e.g.

Website.objects.select_related()

so that it will automatically do a join and follow all of those foreign keys when the query is performed instead of loading them on demand as they are used. Django loads data from the database lazily, so by default you get the following behavior

# one database query
website = Website.objects.get(id=123)

# first time account is referenced, so another query
print website.account.username 

# account has already been loaded, so no new query
print website.account.email_address

# first time registrar is referenced, so another query
print website.registrar.name

and so on. If you use selected related, then a join is performed behind the scenes and all of these foreign keys are automatically followed and loaded on the first query, so only one database query is performed. So in the above example, you'd get

# one database query with a join and all foreign keys followed
website = Website.objects.select_related().get(id=123)

# no additional query is needed because the data is already loaded
print website.account.username
print website.account.email_address
print website.registrar.name
Eli Courtwright
Thank you! That definitely makes a lot of sense to have that function. Now it's running 9 queries. Since the tables are small, I don't care that it's loading all the data (and obviously it's way better to).
Dan Breen