From 1472cb5b7ebc8d4a6517a29afe149aedc3b69c2c Mon Sep 17 00:00:00 2001 From: Razmig Sarkissian Date: Wed, 12 Mar 2025 10:35:33 +0100 Subject: [PATCH] fix loading tournaments --- tournaments/models/group_stage.py | 5 ++- tournaments/models/tournament.py | 34 ++++++++++------ tournaments/views.py | 64 ++++++++++++++++++++++++------- 3 files changed, 77 insertions(+), 26 deletions(-) diff --git a/tournaments/models/group_stage.py b/tournaments/models/group_stage.py index c1fa9a8..76b5d11 100644 --- a/tournaments/models/group_stage.py +++ b/tournaments/models/group_stage.py @@ -5,6 +5,7 @@ import uuid from ..utils.extensions import format_seconds from datetime import datetime, timedelta from django.utils import timezone +from django.db.models import Count, Q class GroupStage(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True) @@ -140,7 +141,9 @@ class GroupStage(models.Model): return False def is_completed(self): - return not self.match_set.filter(end_date__isnull=True).exists() and self.match_set.count() > 0 + # This will use the prefetched matches if available + matches = list(self.match_set.all()) + return len(matches) > 0 and all(match.end_date is not None for match in matches) class LiveGroupStage: def __init__(self, title, step, index): diff --git a/tournaments/models/tournament.py b/tournaments/models/tournament.py index 9dd1a8c..270530a 100644 --- a/tournaments/models/tournament.py +++ b/tournaments/models/tournament.py @@ -970,22 +970,21 @@ class Tournament(models.Model): def nearly_over(self): # First check group stages if they exist - if self.groupstage_set.count() > 0: + group_stages = list(self.groupstage_set.all()) # Use prefetched data + if group_stages: # Check if all group stages are completed - for group_stage in self.groupstage_set.all(): + for group_stage in group_stages: + # Use the is_completed method if group_stage.is_completed(): return True # If no group stages, check semi-finals - if self.round_set.count() > 0: - # Get round with index 1 (semi-finals) and no parent - semifinals = self.round_set.filter(index=1, parent=None).first() - if semifinals: - # Check if any match in semi-finals has started - for match in semifinals.match_set.all(): - if match.start_date is not None and match.is_ready(): - return True - return False + semifinals = self.round_set.filter(index=1, parent=None).first() # Use prefetched data + if semifinals: + # Check if any match in semi-finals has started + for match in semifinals.match_set.all(): # Use prefetched data + if match.start_date is not None and match.is_ready(): + return True return False @@ -996,7 +995,18 @@ class Tournament(models.Model): return self.hide_teams_weight def is_build_and_not_empty(self): - return self.groupstage_set.count() > 0 or self.round_set.count() > 0 and self.teamregistration_set.count() >= 4 + if hasattr(self, '_prefetched_objects_cache'): + # Use prefetched data if available + has_group_stages = 'groupstage_set' in self._prefetched_objects_cache and len(self.groupstage_set.all()) > 0 + has_rounds = 'round_set' in self._prefetched_objects_cache and len(self.round_set.all()) > 0 + has_team_registrations = 'teamregistration_set' in self._prefetched_objects_cache and len(self.teamregistration_set.all()) >= 4 + else: + # Fall back to database queries if not prefetched + has_group_stages = self.groupstage_set.count() > 0 + has_rounds = self.round_set.count() > 0 + has_team_registrations = self.teamregistration_set.count() >= 4 + + return (has_group_stages or has_rounds) and has_team_registrations def day_duration_formatted(self): return plural_format("jour", self.day_duration) diff --git a/tournaments/views.py b/tournaments/views.py index 5fb9549..df8b489 100644 --- a/tournaments/views.py +++ b/tournaments/views.py @@ -57,7 +57,6 @@ from django.contrib.auth.forms import ( from django.contrib.auth.views import PasswordResetConfirmView from django.contrib.auth import get_user_model from django.contrib.auth.tokens import default_token_generator -from django.db.models import Q from django.views.decorators.csrf import csrf_exempt from django.core.files.storage import default_storage from django.core.files.base import ContentFile @@ -108,9 +107,20 @@ from .forms import CustomPasswordChangeForm def index(request): club_id = request.GET.get('club') - future = future_tournaments(club_id) - live = live_tournaments(club_id) - finished = finished_tournaments(club_id) + tournaments = tournaments_query(Q(end_date__isnull=True), club_id, True, 50) + display_tournament = [t for t in tournaments if t.display_tournament()] + live = [t for t in display_tournament if t.supposedly_in_progress()] + future = [t for t in display_tournament if t.starts_in_the_future()] + + clean_ended_tournaments = tournaments_query(Q(end_date__isnull=False), club_id, False, 50) + clean_ended_tournaments = [t for t in clean_ended_tournaments if t.display_tournament()] + ended_tournaments = [t for t in display_tournament if t.should_be_over()] + + # Combine both lists + finished = clean_ended_tournaments + ended_tournaments + + # Sort the combined list by start_date in descending order + finished.sort(key=lambda t: t.start_date, reverse=True) club = None if club_id: @@ -127,7 +137,7 @@ def index(request): } ) -def tournaments_query(query, club_id, ascending): +def tournaments_query(query, club_id, ascending, limit=None): queries = [query, Q(is_private=False, is_deleted=False, event__club__isnull=False)] club = None @@ -139,18 +149,46 @@ def tournaments_query(query, club_id, ascending): sortkey = 'start_date' if not ascending: sortkey = '-start_date' - return Tournament.objects.filter(*queries).order_by(sortkey) -def finished_tournaments(club_id): - ended_tournaments = tournaments_query(Q(is_private=False, is_deleted=False, event__club__isnull=False), club_id, False) - return [t for t in ended_tournaments if t.display_tournament() and t.should_be_over()] + queryset = Tournament.objects.filter(*queries).prefetch_related( + 'groupstage_set', + 'round_set', + 'teamregistration_set', + ).order_by(sortkey) + + # Apply limit directly in the database query + if limit is not None and isinstance(limit, int) and limit > 0: + queryset = queryset[:limit] + + return queryset + +def finished_tournaments(club_id, limit=None): + clean_ended_tournaments = tournaments_query(Q(end_date__isnull=False), club_id, False, limit) + clean_ended_tournaments = [t for t in clean_ended_tournaments if t.display_tournament()] + + one_day_ago = timezone.now() - timedelta(days=1) + ended_tournaments = tournaments_query( + Q(end_date__isnull=True, start_date__lt=one_day_ago), + club_id, + False, + limit + ) + ended_tournaments = [t for t in ended_tournaments if t.display_tournament() and t.should_be_over()] + + # Combine both lists + all_tournaments = clean_ended_tournaments + ended_tournaments + + # Sort the combined list by start_date in descending order + all_tournaments.sort(key=lambda t: t.start_date, reverse=True) + + return all_tournaments -def live_tournaments(club_id): - tournaments = tournaments_query(Q(end_date__isnull=True), club_id, True) +def live_tournaments(club_id, limit=None): + tournaments = tournaments_query(Q(end_date__isnull=True), club_id, True, limit) return [t for t in tournaments if t.display_tournament() and t.supposedly_in_progress()] -def future_tournaments(club_id): - tournaments = tournaments_query(Q(end_date__isnull=True), club_id, True) +def future_tournaments(club_id, limit=None): + tournaments = tournaments_query(Q(end_date__isnull=True), club_id, True, limit) return [t for t in tournaments if t.display_tournament() and t.starts_in_the_future()] def tournament_info(request, tournament_id):