Saturday, March 7, 2009

Django and fetching of foreign keys on attribute access.

Today I noticed something funny about how, and when, Django automatically fetches related objects.

With this simple model;


from django.db import models

class Blog(models.Model):
title = models.CharField(max_length=128)

def __unicode__(self):
return self.title

class Article(models.Model):
body = models.TextField()
blog = models.ForeignKey(Blog)


If you fetch the article and access it's blog.id field, the related object is automatically
fetched, as we can see by investigating the instances _blog_cache field:


>>> blog = Blog.objects.create(title="My Blog")
>>> article = Article.objects.create(body="The quick brown fox...", blog=blog)
>>> article.blog.id
1
>>> article._blog_cache
<Blog: My Blog>


However, if you have no interest in fetching
the related object, there seems to be a workaround: the blog_id field, just check it out;


>>> article = Article.objects.all()[0]
>>> article.blog_id
1
>>> article._blog_cache
AttributeError: 'Article' object has no attribute '_blog_cache'

1 comment:

  1. As soon as you access the '.blog' attribute, the .blog object has to be fetched, so this doesn't seem 'funny' to me.

    We did, actually, at one point toy with the idea of the returned object also being lazy, so that 'article.blog' would give you an object with only the '.id' attribute set, and any other attribute access would force retrieval of the rest. But we decided it was likely to be more pain than it was worth. The current behaviour is quite easy to understand, and you can easily just access the foreign key value if you want (as you described).

    ReplyDelete