Джанго: оптимизация запросов - PullRequest
2 голосов
/ 31 декабря 2010

Я хочу перечислить количество элементов для каждого списка.Как я могу найти это число в одном запросе, а не в запросе для каждого списка?

Вот упрощенная версия моего текущего шаблона кода:

{% for list in lists %}
<li>
{{ listname }}:
{% with list.num_items as item_count %}
{{ item_count }} item{{ item_count|pluralize }}
{% endwith %}
</li>
{% endfor %}

списки передаются как:List.objects.filter (user = user)

, а num_items является свойством модели списка:

def _get_num_items(self):
    return self.item_set.filter(archived=False).count()
num_items = property(_get_num_items)

Этот запрос SELECT COUNT(*) FROM "my_app_item" WHERE... n раз, где n - количество списков,Здесь можно сделать один запрос?

Ответы [ 2 ]

1 голос
/ 31 декабря 2010

В дальнейшем я попытался учесть все ваши ограничения: фильтрация по полям List, по полям Item, подсчет предметов и группировка по списку.

Решение, которое я вижу, состоит в том, что вы могли быиспользуйте values ​​() (вот документ django об этом: http://docs.djangoproject.com/en/dev/topics/db/aggregation/#values)

from django.db.models import Count
lists = list(List.objects.filter(user=user))
items=Item.objects.values(list).filter(archived=False,list__in=lists).annotate(count=Count("id")) 
#you will get a list of dicts of the form [{'count':2,'list':5},...] where 5 is the id of the list
#now, you can match you list with you item counts in python
list_items_count_dict={}
for item in items:
    list_items_count_dict[item['list']]=item['count']
for list in lists : 
    list.item_count = list_items_count_dict.get(list.id)

, который сделает только 2 запроса, один для получения списков, другой для вычисления количества элементов. После этого вы будетеиметь два цикла (которые, вероятно, можно заменить однострочными для понимания списков), но только для интересующих вас списков.

впоследствии, в своем шаблоне вы можете использовать

{{list.item_count}}

Возможно, есть более элегантный вариант, но это то, что я нашел прямо сейчас. Я также уверен, что вы можете уменьшить количество запросов до одного, используя пользовательский sql.

Отказ от ответственности: я не проверялэтот код, но я тестировал похожий код на похожих моделях. У вас могут быть проблемы, потому что list является одним из ключевых слов языка Python.

1 голос
/ 31 декабря 2010

Вы должны сделать это в своем представлении и вместо этого отправить словарь.

Model.objects.values_list('item').annotate(Count('num_items'))

Это приведет к тому, что SQL будет таким же (или эквивалентным) тому, который вы опубликовали.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...