首页 > 解决方案 > 如何从 Django 中的 ManyToManyField 计算查询集?

问题描述

在模型中:

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

标签: djangodjango-modelsdjango-views

解决方案


这里的问题是它match不是一个对象Match,它是一个QuerySet包含零个、一个或多个Match对象的对象。因此你不能使用hot_league这样的关系QuerySet

如果你想计算所有属于 的HotLeaguesrequest.user并且有一个Match属于那个request.user的,你可以把它算作:

HotLeague.objects.filter(user=request.user, match__user=request.user).count()

如果它属于as的多个匹配项,这将多次计算相同 的值。如果你希望每个只计算一次,你可以添加一个[Django-doc]到它:HotLeaguerequest.useruserHotLeague.distinct()

HotLeague.objects.filter(user=request.user, match__user=request.user).distinct().count()

或者,您可以使用该用户的 s 数量来注释Matches 的数量HotLeague,例如:

from django.db.models import Count, Q

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

Match源自该查询集的每个都将具有一个额外的属性,该属性nhotleagues指定该HotLeague用户的 s 数。所以你可以这样渲染:

{% for match in matches %}
    {{ match.pk }}: {{ match.notleagues }}<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)) +
          Count('mega_league', distinct=True, filter=Q(megaleague__user=request.user)) +
          Count('head_to_head_league', distinct=True, filter=Q(head_to_head_league__user=request.user))
)

当然,您在 JOIN 中添加的表越多,查询的开销就越大。


推荐阅读