Django: одновременное использование двух связанных полей / внешних ключей

У меня есть три модели:

class Team(models.Model):
    team_id = models.AutoField()
    team_name = models.CharField()

class Game(models.Model):
    game_id = models.AutoField()
    home_team = models.ForeignKey(Team, on_delete=models.CASCADE)
    away_team = models.ForeignKey(Team, on_delete=models.CASCADE)

class TeamBoxScore(models.Model):
    game = models.ForeignKey(Game, on_delete=models.CASCADE, related_name='game_boxscore')
    team = models.ForeignKey(Team, on_delete=models.CASCADE, related_name='team_boxscore')
    # some stats here

Я хочу, чтобы для каждого экземпляра игры был доступ к TeamBoxScore , который соответствует как Game экземпляру, так и Team экземпляру, на который ссылается home_team/away_team.

Есть ли способ сделать так, чтобы game.home_team.team_boxscore ссылался только на boxscore для этого game_id? Или, наоборот, я могу указать, какой game.game_boxscore я хочу вернуть (тот, который соответствует home_team или тот, который соответствует away_team)? Я хочу минимизировать количество запросов и избежать длительных итеративных решений.

Я пробовал аннотировать поля из каждого экземпляра TeamBoxScore в каждый Game (ссылаясь на связанное поле game_boxscore), но это приводит к удвоению размера набора запросов и размещению значений из домашнего и гостевого бокскора в отдельных экземплярах. Я пробовал обращаться к связанному полю team_boxscore, но это возвращает все бокс-коры для этой команды (game.home_team.team_boxscore).

Далее я попытался сгруппировать эти аннотированные значения и просто вернуть сумму, но это и неэлегантно, и занимает слишком много времени (и может быть неправильно!)

Я пробовал использовать фильтрованный набор запросов на Prefetch:

home_team_boxscore_prefetch = Prefetch(
        'home_team__team_boxscore',
        queryset=TeamBoxScore.objects.filter(game_id=F('game__game_id'),   team_id=F('game__home_team__team_id')),
        to_attr='home_team_boxscore'
    )

и затем передаем его в prefetch_related, но это почему-то возвращает все домашние игры команды home_team. Есть идеи? Мне кажется, что я упускаю что-то очень простое.

Пробовали ли вы вместо этого аннотировать идентификаторы TeamBoxScore?

from django.db.models import Case, When, F, Value, IntegerField

games = Game.objects.filter(**game_filters)

# Annotate each Game instance with the corresponding TeamBoxScore based on home_team or away_team
games_with_boxscores = games.annotate(
    home_team_boxscore_id=Case(
        When(home_team_id=F('home_team__team_id'), then=F('game_boxscore')),
        default=Value(None),
        output_field=IntegerField(),
    ),
    away_team_boxscore_id=Case(
        When(away_team_id=F('away_team__team_id'), then=F('game_boxscore')),
        default=Value(None),
        output_field=IntegerField(),
    )
)

for game in games_with_boxscores:
    home_team_boxscore = TeamBoxScore.objects.filter(id=game.home_team_boxscore_id).first()
    away_team_boxscore = TeamBoxScore.objects.filter(id=game.away_team_boxscore_id).first()

    # Do whatever you need with the boxscores

Вернуться на верх