0

I am trying to make some efficient queries with Django in the following loop:

for division in divisions:
  playoffs = league.playoff_set.filter(division=division, double_elimination=True)

I thought maybe filtering playoffs before the loop by selecting only those with double_elimination=True would enhance it:

playoffs = league.playoff_set.filter(double_elimination=True)
for division in divisions:
  division_playoffs = playoffs.filter(division=division)

But now I am concerned that this is firing the query from playoffs in every run at the loop instead of filtering on the previously retrieved result.

Is it working as expected or as I am fearing? Should I use Q instead to build these better-performing queries?

Alasdair
  • 298,606
  • 55
  • 578
  • 516
dabadaba
  • 9,064
  • 21
  • 85
  • 155

1 Answers1

6

Django querysets are lazy. That means that the queryset isn't evaluated when you do

playoffs = league.playoff_set.filter(double_elimination=True)

It isn't even evaluated when you filter the queryset again in the loop.

division_playoffs = playoffs.filter(division=division)

The queryset will only be evaluated when you access its contents (either in the view or in the template).

playoffs = league.playoff_set.filter(double_elimination=True)
for division in divisions:
    division_playoffs = playoffs.filter(division=division)
    for playoff in division_playoffs:  # looping through queryset causes it to be evaluated
        print(playoff)

Therefore, both versions of your code will work the same. you should choose the one that you find to be clearer.

Alasdair
  • 298,606
  • 55
  • 578
  • 516
  • So even if I stayed with the original approach (when the query was `playoffs = league.playoff_set.filter(division=division, double_elimination=True)` in every loop) it would be as efficient? – dabadaba Dec 02 '16 at 12:15
  • You can use something like the Django debug toolbar to look at the resulting SQL queries. As I said, both versions of your code will work the same. – Alasdair Dec 02 '16 at 12:18
  • You can view SQL queries that have been run, might help you understand whats happning under the hood. http://stackoverflow.com/questions/1074212/how-to-show-the-sql-django-is-running If there is a significant number of divisions, but not a overwhelming number of playoffs, it may be best just to query `league.playoff_set.filter(double_elimination=True)` and then group the results in python. eg. http://stackoverflow.com/questions/31071888/python-group-list-items-in-a-dict – Trevor Ian Peacock Dec 02 '16 at 12:23