我发现当我尝试打开对象创建窗口FriendlyMatch时,需要花费很多时间。大约2分钟。通过django调试工具栏我发现有4300个SQL查询。这是我的模型:
class Player(models.Model):
"""Модель игрока"""
user = models.ForeignKey(
User, related_name="player", on_delete=models.CASCADE, verbose_name="Игрок"
)
created = models.DateTimeField(auto_now_add=True)
team = models.ForeignKey(
Team,
related_name="team_player",
null=True,
on_delete=models.SET_NULL,
verbose_name="Команда",
)
class Meta:
"""Мета класс модели Игрока"""
verbose_name = "Игрок"
verbose_name_plural = "Игроки"
def __str__(self):
return f"Игрок {self.user.username}"
class FriendlyMatch(models.Model):
"""Модель Дружеского матча"""
date_start = models.DateTimeField(
verbose_name="Дата и время начала", null=True, blank=True
)
date_end = models.DateTimeField(
verbose_name="Дата и время окончания", null=True, blank=True
)
duration_macth = models.SmallIntegerField(
verbose_name="Длительность дружеского матча", default=3, null=True, blank=True
)
creator = models.ForeignKey(
User,
related_name="creator_friendly_match",
null=True,
on_delete=models.SET_NULL,
verbose_name="Создатель",
)
player_1 = models.ForeignKey(
Player,
related_name="friendly_match_player1",
null=True,
on_delete=models.SET_NULL,
verbose_name="Игрок 1",
)
player_2 = models.ForeignKey(
Player,
related_name="friendly_match_player2",
null=True,
blank=True,
on_delete=models.SET_NULL,
verbose_name="Игрок 2",
)
first_game_winner = models.ForeignKey(
Player,
related_name="first_game_winner_friendly_match",
null=True,
blank=True,
on_delete=models.SET_NULL,
verbose_name="Победитель первой игры",
)
second_game_winner = models.ForeignKey(
Player,
related_name="second_game_winner_friendly_match",
null=True,
blank=True,
on_delete=models.SET_NULL,
verbose_name="Победитель второй игры",
)
third_game_winner = models.ForeignKey(
Player,
related_name="third_game_winner_friendly_match",
null=True,
blank=True,
on_delete=models.SET_NULL,
verbose_name="Победитель третьей игры",
)
fourth_game_winner = models.ForeignKey(
Player,
related_name="fourth_game_winner_friendly_match",
null=True,
blank=True,
on_delete=models.SET_NULL,
verbose_name="Победитель четвертой игры",
)
fifth_game_winner = models.ForeignKey(
Player,
related_name="fifth_game_winner_friendly_match",
null=True,
blank=True,
on_delete=models.SET_NULL,
verbose_name="Победитель пятой игры",
)
winner = models.ForeignKey(
Player,
related_name="friendly_match_winner_friendly_match",
on_delete=models.CASCADE,
verbose_name="Победитель",
null=True,
blank=True,
)
status_friendly_match = models.CharField(
verbose_name="Статус дружеского матча",
choices=StatusChoices.choices,
max_length=64,
default=StatusChoices.NOT_STARTED,
)
class Meta:
"""Мета класс для Дружеского матча"""
verbose_name = "Дружеский матч"
verbose_name_plural = "Дружеский матчи"
这是我的FriendlyMatch模型的管理模型:
@admin.register(FriendlyMatch)
class FriendlyMatchAdmin(admin.ModelAdmin):
list_display = ("id", "date_start", "player_1", "player_2", "status_friendly_match")
在寻找解决方案时,发现这是受到相关模型的str方法的影响。我从 Player 模型中删除了 str 方法,然后查询数量减少,并且 SQL 查询一切都变得正常。如何在不从 Player 模型中删除 str 方法的情况下优化查询?
您可以使用 list_select_lated 告诉 Django modeladmin 类使用 select_lated() 来检索管理更改列表页面上的对象列表。这可以为您节省大量数据库查询。
您还可以结合 only() 方法来指定要在查询集中检索的字段集。
@admin.register(FriendlyMatch)
class FriendlyMatchAdmin(admin.ModelAdmin):
list_display = ("id", "date_start", "player_1", "player_2", "status_friendly_match")
list_select_related = ["player_1", "player_2"]
def get_queryset(self, request):
qs = super().get_queryset(request)
qs = qs.only(
"id", "date_start", "status_friendly_match", "player_1_id", "player_1__user", "player_2_id", "player_2__user"
)
return qs
如果您想在一次查询中显示玩家的用户名和数据检索。您可以使用下面的代码。
@admin.register(FriendlyMatch)
class FriendlyMatchAdmin(admin.ModelAdmin):
list_display = ("id", "date_start", "player_1", "player_2", "status_friendly_match")
list_select_related = ["player_1", "player_2", "player_1__user", "player_2__user"]
def get_queryset(self, request):
qs = super().get_queryset(request)
qs = qs.only(
"id", "date_start", "status_friendly_match", "player_1_id", "player_1__user__username", "player_2_id", "player_2__user__username"
)
return qs