gpt4 book ai didi

python - 使用 Django ORM 从相关表中获取数据

转载 作者:行者123 更新时间:2023-12-04 08:35:16 25 4
gpt4 key购买 nike

使用 Django ORM,如何在不对每条记录进行有效的单独调用(或对数据进行冗余非规范化以使其更易于访问)的情况下访问相关表中的数据?

假设我有 3 个模型:

class Tournament(models.Model):
name = models.CharField(max_length=250)
active = models.BooleanField(null=True,default=1)

class Team(models.Model):
name = models.CharField(max_length=250)
coach_name = models.CharField(max_length=250)
active = models.BooleanField(null=True,default=1)

class Player(models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.DO_NOTHING
)
number = models.PositiveIntegerField()
age = models.PositiveIntegerField()
active = models.BooleanField(null=True,default=1)

请注意,此 Player 模型在应用程序中很重要,因为它是大多数模型的主要连接 - 从注册到团队到统计数据到结果再到奖品。但是这个 Player 模型实际上并不包含人名,因为该模型包含一个用户字段,该字段是自定义 AUTH_USER_MODEL(“用户”)模型的外键,该模型包含名字/姓氏信息。这允许玩家登录到应用程序并执行某些操作。

除了这些基本模型外,假设一个玩家可以在不同的锦标赛中参加不同的球队,我还有一个连接的 ManyToMany 模型:

class PlayerToTeam(models.Model):
player = models.ForeignKey(
Player,
on_delete=models.DO_NOTHING
)
team = models.ForeignKey(
Team,
on_delete=models.DO_NOTHING
)
tournament = models.ForeignKey(
Tournament,
on_delete=models.DO_NOTHING
)

作为我遇到的挑战之一的示例,假设我正在尝试创建一个允许教练选择他们的首发阵容的表单。所以我需要我的表格来列出特定锦标赛中特定团队的球员姓名。

鉴于锦标赛和团队 ID,我可以轻松地提取必要的 QuerySet 来描述我感兴趣的初始记录。

playersOnTeam = PlayerToTeam.objects.filter(tournament=[Tournament_id]).filter(team=[Team_id])

这将返回球队、锦标赛和球员的 ID(但仅是 ID)的查询集。但是,名称数据相差两个模型:

PlayerToTeam->[player_id]->Player->[user_id]->User->[first_name] [last_name]

现在,如果我只拉回一条记录,我可以简单地做

onlyPlayerOnTeam = PlayerToTeam.objects.filter(tournament=[Tournament_id]).filter(team=[Team_id]).filter(player=[Player_id]).get()

onlyPlayerOnTeam.player.user.first_name

因此,如果我只需要显示名称,我相信我可以在 View 返回中传递 QuerySet 并在模板中循环它并显示我需要的内容。但是当我需要将名称显示为表单的一部分时,我不知道您是否可以做类似的事情。

为了填充表单,我相信我可以遍历初始 QuerySet 并构建一个新的数据结构:

playersOnTeam = PlayerToTeam.objects.filter(tournament=[Tournament_id]).filter(team=[Team_id])

allPlayersData= []
for nextPlayer in playersOnTeam:
playerDetails= {
"player_id": nextPlayer.player.id,
"first_name": nextPlayer.player.user.first_name,
"last_name": nextPlayer.player.user.last_name,
}
allPlayersData.append(playerDetails)

form = StartingLineupForm(allPlayersData)

但是,我担心这会导致为每个玩家/用户调用单独的数据库!

虽然这对于 6-10 名玩家来说可能是可以接受的,但对于更大的数据集来说,这似乎不太理想。循环为每个用户执行查询似乎是完全错误的。

此外,令人沮丧的是,使用直接的 SQL 查询就足够简单了:

SELECT User.first_name, User.last_name 
FROM PlayerToTeam
INNER JOIN Player ON PlayerToTeam.player_id = Player.id
INNER JOIN User ON Player.user_id = User.id
WHERE PlayerToTeam.tournament_id=[tourney_id] AND PlayerToTeam.team_id=[team_id]

但我正在尝试尽可能多地坚持 Django ORM 最佳实践,避免在我无法立即解决问题时直接使用 SQL 查询,而且我几乎可以肯定这不是情况如此复杂,如果不求助于直接 SQL 查询,我将无法完成此任务。

我开始研究 select_relatedprefetch_related,但我无法理解它们如何为关系工作,而不仅仅是一个表连接.好像我可以使用预取访问 Player.age 数据,但我不知道如何从中获取 User.first_name

如有任何帮助,我们将不胜感激。

最佳答案

  1. 我建议两种方法:

A) 选择相关(一个数据库查询):

objects = PlayerToTeam.objects.filter(
...
).select_related(
'player__user',
).only('player__user__name')

name = objects.first().user.name

B) 注释(一个数据库查询):

objects = PlayerToTeam.objects.filter(
...
).annotate(
player_name=F('player__user__name'),
)

name = objects.first().player_name
  1. 为确保您只有一个对象用于特定的playerteamtournament,我建议添加unique_together:
class PlayerToTeam(models.Model):
...

class Meta:
unique_together = ('player', 'team', 'tournament', )

关于python - 使用 Django ORM 从相关表中获取数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64830267/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com