1

Suppose I have two related models

class Foo(models.Model):
    value = models.FloatField()

class Bar(models.Model):
    multiplier = models.FloatField()
    foo = models.ForeignKey(Foo, related_name="bars")

    def multiply(self):
        return self.foo.value * self.multiplier

An instance of Foo will frequently have many instances of Bar, but some information that is relevant for a calculation that Bar does is stored in Foo (because it is the same for all instances of related Bars)

The problem is when I do something like this:

foo = Foo.objects.latest()
[x.multiply() for x in foo.bars.all()]

It ends up hitting the database a lot because every Bar object in foo.bars.all() queries the database for the Foo object. So, if I have 10 Bars, then I will incur 11 database queries (1 to get the queryset with 10 bars, and 1 for each Bar object reaching back to get self.foo.value). Using select_related() doesn't seem to help.

My questions are: 1) Am I correct in thinking that memcached (e.g. Johnny Cache, Cache Machine) will solve this problem? 2) Is there a way of designing the object relationship that can make the command more efficient without a cache?

2
  • why would it be 11 queries? it would be just 2 queries. Commented May 30, 2013 at 23:31
  • Sorry, that was a typo, should be [x.multiply() for x in foo.bars.all()]. Because multiply() requires a value that is stored in foo, so each call of multiply() has to retrieve foo. Commented May 30, 2013 at 23:32

1 Answer 1

3

It is precisely this kind of situation for which select_related and prefetch_related were created. When you query using these, Django's ORM will employ one of two techniques to avoid redundant database requests: following relations via JOINs (select_related) or pre-caching one-to-many / many-to-many relations in their QuerySets.

# Hits the database
foo = Foo.objects.prefetch_related('bars').latest()

# Doesn't hit the database
[x.value for x in foo.bars.all()]
Sign up to request clarification or add additional context in comments.

1 Comment

prefetch_related() was it. Thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.