Получение данных поля M2M в шаблоне Django
Я хочу получить данные m2m в моем шаблоне через представления, но не могу этого сделать. Дело в том, что я могу показать данные поля m2m, зацикливая их из самого шаблона, но это замедляет работу сайта.
Моя модель командных приложений выглядит следующим образом:
class Team(models.Model):
title = models.CharField(max_length=255)
team_country = CountryField(max_length=200, blank=True, null=True)
members = models.ManyToManyField(User, related_name='teams')
created_by = models.ForeignKey(User, related_name='created_teams', on_delete=models.CASCADE)
Теперь в моем турнирном приложении я пытаюсь получить "членов" команды.
Мои турнирные представления выглядят следующим образом:
def tournament_page(request, slug):
page = 'tournament_page'
user = request.user
tournament = Tournament.objects.get(slug=slug)
players = tournament.participants.select_related('user')
all_players = Profile.objects.select_related('user')
side_tourneys_ongoing = Tournament.objects.filter(state='Ongoing')[:10]
side_tourneys_upcoming = Tournament.objects.filter(state='Upcoming')[:10]
side_tourneys_completed = Tournament.objects.filter(state='Completed')[:10]
teams = Team.objects.select_related('created_by')
context = {
'page': page,
'tournament': tournament,
'side_tourneys_ongoing': side_tourneys_ongoing,
'side_tourneys_upcoming': side_tourneys_upcoming,
'side_tourneys_completed': side_tourneys_completed,
'teams': teams,
'players':players,
'all_players':all_players
}
Теперь я могу показать команды с их членами в шаблоне, используя цикл for в самом шаблоне, как:
Html шаблон
<div class="grid-x">
{% for team in teams %}
{% for player in players %}
{% if team.id == player.active_team_id and team.game == tournament.game %}
<div class="wf-card event-team">
<div> {{team.title}} </div>
<div class="event-team-players">
{% for member in team.members.all %}
{{ member.username }}
{% endfor %}
</div>
</div>
{% endif %}
{% endfor %}
{% endfor %}
</div>
Что я хочу, так это использовать этот фрагмент кода
{% for member in team.members.all %}
{{ member.username }}
{% endfor %}
в моих представлениях, поскольку это приводит к замедлению работы сайта, и я не знаю почему.
Что я пробовал в своих представлениях, это:
all_teams = Team.objects.all()
members = all_teams.members.all()
и
members = Team.objects.all().prefetch_related('members')
Первый выдает ошибку:
У объекта 'QuerySet' нет атрибута 'members'
Второй показывает много пустых записей
Пробовал почти все с помощью поиска, но ни один из них не помог, кроме использования кода, который я предоставил непосредственно в самом шаблоне.
Думаю, у вас уже есть эта информация. Вы ограничиваете появление игрока только player.active_team, а не всеми его командами, поэтому вам не нужно делать отдельный вызов. Я подозреваю, что ваши циклы player и member таким образом также удваиваются - вы делаете sql вызов team.members.all
для каждого игрока*каждой команды как есть Вот один способ обработки, который может работать немного лучше (непроверенный код, извините)
<div class="grid-x">
{% for team in teams %}
{% if team.game == tournament.game %}
<div class="wf-card event-team">
<div> {{team.title}} </div>
<div class="event-team-players">
{% for player in players %}
{% if team.id == player.active_team_id %}
{{ player.user.username }}
{% endif %}
{% endfor %}
</div>
</div>
{% endif %}
{% endfor %}
</div>
Если вы хотите, чтобы игрок отображался во всех своих командах, вы можете попробовать получить информацию о командах одновременно с помощью prefetch_related
players = tournament.participants.select_related('user').prefetch_related('user__teams')
тогда в вашем шаблоне вы можете просто посмотреть, находится ли текущая команда в связанной группе команд.
{% for player in players %}
<div class="event-team-players">
{% if team in player.user.teams %}
{{ player.user.username }}
{% endif %}
{% endfor %}
Это немного эффективнее, так как вся информация о командах предварительно загружена, поэтому вам не нужно вызывать sql для каждой команды.