请参考这些示例模型。
class Player(models.Model):
team = models.ForeignKey(Team, on_delete=models.CASCADE)
class Team(models.Model):
captain = models.ForeignKey(Manager, on_delete=models.CASCADE)
country = models.CharField()
class Manager(models.Model):
networth = models.FloatField()
我想知道下面的方法是否比其他方法快(即访问数据库的次数少)。
team = Team.objects.get()
Player.objects.filter(team_id=team.id)
替代方案。
team = Team.objects.get()
Player.objects.filter(team=team)
我想知道下面的方法是否比另一种方法快
没有. 这将导致 一样 查询。除了Django会花几个周期来检查你传递的内容和访问主键外,没有任何区别。
你可以在The Django shell中用检查。
>>> print(Player.objects.filter(team_id=team.id).query)
SELECT `app_name_player`.`id`, `app_name_player`.`team_id` FROM `app_name_player` WHERE `app_name_player`.`team_id` = 1
>>> print(Player.objects.filter(team=team).query)
SELECT `app_name_player`.`id`, `app_name_player`.`team_id` FROM `app_name_player` WHERE `app_name_player`.`team_id` = 1
所以这两个查询是一样的 可能用取这些更习惯。
team.player_set.all()
如果你需要访问 Player
一套 Team
的,你可以利用 .prefetch_related(…)
[Django-doc] 来获取所有的 Player
为一个 设置 的团队,避免了在一次查询中出现 N+1 问题。
teams = Team.objects.prefetch_related('player_set')
在这里,如果你然后迭代过 teams
,并取来 player_set
每个 Team
对象,它不会进行额外的查询,因为它已经获取了所有相关的 Player
的一个额外查询,并在PythonDjango层做了 "加入"。
所以为了更好的说明我在注释中的观点--我在野外经常看到的是这样的url结构。
/teams/<int:pk>/players/
伴随着这样的视图代码
def players_view(request, pk):
team = Team.objects.get(pk=pk)
context = {
"players": Player.objects.filter(team=team)
}
...
而你可以直接这样做
def players_view(request, pk):
context = {
"players": Player.objects.filter(team__pk=pk)
}
...
而你可以直接做:
def players_view(request, pk):
context = {
"players": Player.objects.filter(team__pk=pk).select_related("team")
}
...
和模板技巧。
{% for player in players %}
<!-- team name only once -->
{% if forloop.first %}
<h1>Players of {{player.team.name}}</h1>
{% endif %}
<!-- data of player here -->
{% endfor %}