我有三个型号:
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
我想要做的是,对于每个 Game 实例,访问与
TeamBoxScore
实例和 Game
/Team
引用的 home_team
实例相匹配的 away_team
。
有没有一种方法可以让
game.home_team.team_boxscore
仅参考该game_id
的评分?或者,相反,我可以指定要返回哪个 game.game_boxscore
(匹配 home_team
的那个还是匹配 away_team
的那个)?我想尽量减少查询并避免长时间的迭代解决方案。
我尝试将每个
TeamBoxScore
实例中的字段注释到每个 Game
(引用 game_boxscore
相关字段),但这最终会使查询集的大小加倍,并放置来自主场得分和客场得分的值单独实例中的 boxcore。我尝试过查看 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 ID?
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