Подсчет более одного вхождения в запросе Django - PullRequest
0 голосов
/ 25 июня 2019

У меня есть две модели: игроки и турниры.

Игроки также имеют тип игры, в которую они играют (дота, лол, магия и т. Д.).Они могут участвовать во многих турнирах одновременно (только один раз за турнир).Для управления надписями я использую другую модель под названием TournamentMatch, которая создает новый объект для каждой надписи с идентификатором турнира и игрока.

class Player(models.Model):
    name = models.CharField(_('name'), max_length=150, null=True, blank=True)
    email = models.EmailField(_('email address'), unique=True)
    is_dota_player = models.BooleanField(default=False)
    is_lol_player = models.BooleanField(default=False)
    is_magic_player = models.BooleanField(default=False)

class Tournament(models.Model):
    name = models.CharField(max_length=200)
    date_start = models.DateField()
    date_end = models.DateField()

class TournamentMatch(models.Model):
    tournament = models.ForeignKey(Tournament)
    player = models.ForeignKey(Player)
    date_added = models.DateTimeField(auto_now_add=True)
    date_modified = models.DateTimeField(auto_now=True)

Я хочу подсчитать количество игроковкоторые имеют более двух надписей на турнирах и являются, например, дота-игроками.

Я легко могу добиться этого с помощью цикла for для каждого игрока, но по причинам производительности я хочу добиться этого, используязапрос Django.

Например, если я хочу посчитать дота-игроков с одной или несколькими надписями, я сделаю:

TournamentMatch.objects.filter(
    player__is_dota_player=True
).distinct(
   'player'
).count()

Я уверен, что возможно, но я нене знаю, как рассчитывать каждое вхождение отдельных игроков на турнирах и фильтровать только тех, у которых более одного (и не только одного).

Я буду признателен за любую помощь или указатели!

1 Ответ

0 голосов
/ 25 июня 2019
# subquery for counting match per player (note OuterRef which will be linked to the outer query row)
player_match_count_subquery = TournamentMatch.objects.filter(player_id=OuterRef('pk'), ).\
    annotate(match_count=Count('pk'), ).values('match_count', )[:1]

# the main (outer) query which uses subquery output for filtering
Players.objects.filter(is_dota_player=True, ).\
    annotate(match_count=Subquery(player_match_count_subquery), ).\
    filter(match_count__gt=2, )

https://docs.djangoproject.com/en/2.2/ref/models/expressions/#subquery-expressions

этот код будет логически выдавать этот SQL-запрос:

SELECT p.*, tm.match_count
FROM players p
CROSS APPLY (
    SELECT COUNT(id) match_count
    FROM tournamentmatch tm
    WHERE tm.player_id = p.id
) tm
WHERE p.is_dota_player = $true
    AND tm.match_count > 2
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...