3 ответов:
хотя Django docs рекомендую использовать
count, а неlen:Примечание: не используйте
len()на QuerySets, если все, что вы хотите сделать, это определить количество записей в наборе. Гораздо эффективнее обрабатывать счетчик на уровне базы данных, используя SQLSELECT COUNT(*), и Django предоставляетcount()способ именно по этой причине.так как вы все равно повторяете этот запрос,результат будет кэшированный (если вы не используете
iterator), и поэтому предпочтительнее будет использоватьlenС это позволяет избежать попадания в базу данных снова, а также, возможно, получения другого количества результатов!).
Если вы используетеiterator, тогда я бы предложил включить переменную подсчета, когда вы повторяете (а не используете count) по тем же причинам.
Я думаю, что с помощью
len(qs)имеет больше смысла здесь, как вам нужно перебирать результаты.qs.count()лучший вариант, если все, что вы хотите сделать, это распечатать счет и не перебрать результаты.
len(qs)попал в базу данныхselect * from table, тогда какqs.count()попадет в БД сselect count(*) from table.и
qs.count()вернет целое число, и вы не можете перебирать его
выбирая между
len()иcount()зависит от ситуации, и стоит глубоко понять, как они работают, чтобы правильно их использовать.позвольте мне дать вам несколько сценариев:
(самое важное) когда вы только хотите знать количество элементов, и вы не планируете обрабатывать их в любом случае важно использовать
count():DO:
queryset.count()- это будет выполнять одинSELECT COUNT(*) some_tableзапрос, все вычисления выполненный на стороне РСУБД, Python просто нужно получить номер результата с фиксированной стоимостью O (1)НЕТ:
len(queryset)- это будет выполнятьSELECT * FROM some_tableзапрос, извлекающий всю таблицу O(N) и требующий дополнительной памяти O (N) для ее хранения. это самое худшее, что можно сделатькогда вы собираетесь получить queryset в любом случае это немного лучше использовать
len()который не вызовет дополнительный запрос к базе данных какcount()бы:len(queryset) # fetching all the data - NO extra cost - data would be fetched anyway in the for loop for obj in queryset: # data is already fetched by len() - using cache passГраф:
queryset.count() # this will perform an extra db query - len() did not for obj in queryset: # fetching data passРеверсированный 2-й случай (когда queryset уже был извлечен):
for obj in queryset: # iteration fetches the data len(queryset) # using already cached data - O(1) no extra cost queryset.count() # using cache - O(1) no extra db query len(queryset) # the same O(1) queryset.count() # the same: no query, O(1)все станет ясно, как только вы взглянете "под капот":
class QuerySet(object): def __init__(self, model=None, query=None, using=None, hints=None): # (...) self._result_cache = None def __len__(self): self._fetch_all() return len(self._result_cache) def _fetch_all(self): if self._result_cache is None: self._result_cache = list(self.iterator()) if self._prefetch_related_lookups and not self._prefetch_done: self._prefetch_related_objects() def count(self): if self._result_cache is not None: return len(self._result_cache) return self.query.get_count(using=self.db)хорошие ссылки в Django docs:
Comments