Как посчитать набор запросов из ManyToManyField в Django? - PullRequest
1 голос
/ 09 июля 2019

В моделях:

class Match(models.Model):
    user = models.ManyToManyField(User, blank=True)
    hot_league = models.ManyToManyField('HotLeague', blank=True)

class HotLeague(models.Model):
    user = models.ManyToManyField(User, blank=True)
    price_pool = models.IntegerField()
    winner = models.IntegerField()

В просмотрах:

match = Match.objects.filter(user=request.user)
hot_league = match.hot_league.filter(user=request.user).count()

Здесь в просмотрах count() не работает.Как я могу сосчитать hot_league, который находится в match ??

1 Ответ

0 голосов
/ 09 июля 2019

Проблема здесь в том, что match это , а не a Match объект, это QuerySet, который содержит ноль, один или более Match объектов. Поэтому вы не можете использовать отношение hot_league на таких QuerySet.

Если вы хотите сосчитать все HotLeague s, которые принадлежат request.user, и иметь Match, который также принадлежит этому request.user, вы можете считать это как:

HotLeague.objects.filter(<b>user=request.user, match__user=request.user</b>).count()

Это будет считать одно и то же HotLeague несколько раз, если оно относится к нескольким матчам с request.user как user. Если вы хотите посчитать каждый HotLeague только один раз, вы можете добавить .distinct() [Django-doc] к нему:

HotLeague.objects.filter(user=request.user, match__user=request.user)<b>.distinct()</b>.count()

Или вы можете аннотировать число Match es числом HotLeague s этого пользователя, например:

from django.db.models import <b>Count, Q</b>

matches = Match.objects.filter(user=request.user).annotate(
    <b>nhotleagues=Count('hotleague', filter=Q(hotleague__user=request.user))</b>
)

Каждый Match, исходящий из этого набора запросов, будет иметь дополнительный атрибут nhotleagues, который указывает число HotLeague с этого пользователя. Таким образом, вы можете сделать это как:

{% for match in matches %}
    {{ match.pk }}: {{ <b>match.notleagues</b> }}<br>
{% endfor %}

Вы можете подвести итоги, например:

from django.db.models import Count, Q

matches = Match.objects.filter(user=request.user).annotate(
    total=Count('hotleague', distinct=True, filter=Q(hotleague__user=request.user)) <b>+</b>
          Count('mega_league', distinct=True, filter=Q(megaleague__user=request.user)) <b>+</b>
          Count('head_to_head_league', distinct=True, filter=Q(head_to_head_league__user=request.user))
)

Хотя, конечно, чем больше таблиц вы добавляете в JOIN, тем дороже будет запрос.

...