MikeN
MikeN

Reputation: 46257

In Django models, does accessing a foreign key multiple times slower than storing it to a temp variable?

E.g. models:

class Player(models.Model):
    Team = models.ForeignKey(Team)

From an efficiency point of view, if you access the "team" of a player multiple times, is it more efficient to store the team in a temp variable?

Is this less efficient:

player = Player.objects.get(id=1)
print "Player is a member of " + str(player.team)
player.team.printRoster()

than this?:

player = Player.objects.get(id=1)
temp = player.team
print "Player is a member of " + str(temp.team)
temp.printRoster()

I feel the answer is No, they are both the same. But have heard different feedback from colleagues and wanted to get an objective viewpoint.

Upvotes: 1

Views: 1757

Answers (2)

marianobianchi
marianobianchi

Reputation: 8488

It's specified here.

Django caches it for you. The question is what are you going to do with these "foreign key" references. For example, if you have a foreign key to a model which its unicode method access another foreign key to print a "friendly" unicode string, depending on how you make the queryset you may hit the database another time.

Let me give you an example to clarify:

class Player(models.Model):
    pname = models.CharField(max_length=20)
    team = models.ForeignKey('Team')

class Team(models.Model):
    tname = models.CharField(max_length=20)
    country = models.ForeignKey('Country')

    def __unicode__(self):
        return self.tname + u' is from ' + self.country.cname

class Country(models.Model):
    cname = models.CharField(max_length=10)

When you do this:

player = Player.objects.get(name=u'Messi')
print player.team

you will hit the database three times, one fot getting the player, one of getting the team and another time to retrieve the country name. If i'm not wrong, the next time you make that "print" statement, django won't hit the database again (i may be wrong, but i think it works that way).

Imagine now that you want to do this for every player, and you have a lot of them. You are going to hit the database three times per player and that can't be good. If you change your query a little, you can do the same hitting the database just once. This is how you can do it:

players = Player.objects.all().select_related('team__country')
for player in players:
    print player.team

I hope this help you to understand how querysets work on Django. Try to read the documentation i linked here. One excelent tool that can help you measuring your querys efficiency is django_toolbar. I highly recommend it.

Upvotes: 5

okm
okm

Reputation: 23871

Django caches it for you, check the code.

You could ensure this by checking

>>> player.team is player.team

Upvotes: 1

Related Questions