len(queryset) performs the count at application level. That is much less efficient than doing
queryset.count(), which does the calculation at database level and just returns the count.
Querysets are lazily evaluated - meaning the records are not read from the database until code interact with the data. Thats's why we can do
queryset.all() without downloading every records from the database.
An example of something that interacts with the data is doing
len(queryset). This will read all the records in the queryset: effectively downloading the database over the internet. Not particularly efficient.
On the other hand doing
queryset.count() handles the calculation at the database level by executing SQL like
SELECT COUNT(*) FROM table.
That means using
queryset.count() makes the code quicker, and improves database performance. Plus imagine the waste in downloading 5000 records only to check the length and throw them away at the end! Having said that though, if the records will need reading after the length if checked, then
len(queryset) can be valid.
If we spot this issue in your GitHub pull request we give this advice:
Django Doctor will run this check by default. No configuration is needed but the check can be turned on/off using check code
queryset-length in your pyproject.toml file.