在Django中直接访问外键ID字段是否更快?

问题描述 投票:0回答:1

请参考这些示例模型。

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)
mysql django django-models django-rest-framework mysql-python
1个回答
1
投票

我想知道下面的方法是否比另一种方法快

没有. 这将导致 一样 查询。除了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层做了 "加入"。


1
投票

所以为了更好的说明我在注释中的观点--我在野外经常看到的是这样的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 %}
© www.soinside.com 2019 - 2024. All rights reserved.