2

So the Django docs state the following:

And to find whether a queryset contains any items:

if some_queryset.exists():
    print("There is at least one object in some_queryset")

Which will be faster than:

if some_queryset:
    print("There is at least one object in some_queryset")

Why is that though? What good reason is there? Often when evaluating a QuerySet in a Boolean context, all a user cares about is whether there's at least one item which presumably is why exists is faster. Why can't __bool__ on QuerySet simply do the same amount of work as exists?

Look at the source code, there seems to be a bit of work involved:

def __bool__(self):
    self._fetch_all()
    return bool(self._result_cache)

But no documentation providing context on why.

For me, simply calling if some_queryset: is much cleaner and more Pythonic.

guettli
  • 25,042
  • 81
  • 346
  • 663
Nobilis
  • 7,310
  • 1
  • 33
  • 67
  • 1
    You missed the paragraph after the one you've quoted: "Additionally, if a some_queryset has not yet been evaluated, but you know that it will be at some point, then using some_queryset.exists() will do more overall work (one query for the existence check plus an extra one to later retrieve the results) than simply using bool(some_queryset), which retrieves the results and then checks if any were returned." – Daniel Roseman Feb 14 '18 at 13:49
  • @DanielRoseman but that's the "how", not the "why", or at least to me it seems that way, I don't understand the need for this difference. If there's was a practical use case on there that clearly illustrated the significance of this distnction, that'd help a lot. – Nobilis Feb 14 '18 at 13:53
  • But it includes the why. This allows you to evaluate the queryset if you know you'll be iterating it later, and avoid that extra query, while leaving `exists()` as the option for when you know you won't be iterating. – Daniel Roseman Feb 14 '18 at 13:55
  • @DanielRoseman Right, so it's just an optimisation shortcut for queries that just need to be non-empty? – Nobilis Feb 14 '18 at 13:57
  • Maybe [this](https://stackoverflow.com/questions/2065329/sql-server-in-vs-exists-performance) answers it. – ascripter Feb 14 '18 at 14:37
  • @ascripter Is this what Django does under the hood? If so, you're welcome to put it in an answer, I'll upvote it and accept it. – Nobilis Feb 14 '18 at 15:43
  • @Nobilis sorry, thought it was easier to prove this and get the query from `.exists()`. You need really dig deep through the source :/ – ascripter Feb 14 '18 at 16:18

1 Answers1

1

bool will be useful when you want to access the data from the queryset at later point of time. SQL query that will be executed in if some_queryset: will be of the type

SELECT #column_names# FROM #table_name# ...

along with some other conditions depending on your queryset.

While SQL query that will be executed in if some_queryset.exists(): will be of the format

SELECT (1) FROM #table_name# ... LIMIT 1

In this SELECT (1) ... returns a column of 1's for every row in the table and LIMIT will restrict the lookup to one entry only.

This change in query will have mainly two advantages:

  1. Lesser time in query execution
  2. Very less data to be transferred over the network
Ritesh Agrawal
  • 791
  • 4
  • 7