# 既存のインポート部分に追加 from rest_framework.decorators import api_view from rest_framework.response import Response from rest_framework import status from rog.models import NewEvent2, Entry import logging from django.db.models import F, Count from django.utils import timezone logger = logging.getLogger(__name__) """ 解説 この実装では以下の処理を行っています: 1.イベントコードとクラス名のパラメータを受け取ります 2.パラメータが不足している場合はエラーを返します 3.指定されたイベントの存在を確認します 4.指定クラスに属する、ゴール済みのチームをスコア降順で取得します 5.各チームについて以下の情報を収集します: - 順位(1から始まる) - チーム基本情報(名前、ゼッケン番号) - スコア - レース時間(スタートからゴールまでの時間) - スタート時間・ゴール時間 - チェックポイント通過数 - オーナー情報(ユーザー名、メールアドレス) 6.ランキングの要約情報も提供します: - イベント情報 - 指定クラスのチーム総数 - ゴール済みチーム数 - 未ゴールチーム数(スタート済みだがゴールしていないチーム) この実装により、イベント管理者やユーザーはリアルタイムのランキング情報を確認できます。 特に結果発表や途中経過の確認に有用です。スコア順にソートされているため、現在の順位が一目でわかります。 """ @api_view(['GET']) def get_ranking(request): """ 指定クラスのランキングを取得 パラメータ: - class: クラス名 - event: イベントコード """ logger.info("get_ranking called") # リクエストからパラメータを取得 class_name = request.query_params.get('class') event_code = request.query_params.get('event') logger.debug(f"Parameters: class={class_name}, event={event_code}") # パラメータ検証 if not all([class_name, event_code]): logger.warning("Missing required parameters") return Response({ "status": "ERROR", "message": "クラス名とイベントコードが必要です" }, status=status.HTTP_400_BAD_REQUEST) try: # イベントの存在確認 event = NewEvent2.objects.filter(event_name=event_code).first() if not event: logger.warning(f"Event not found: {event_code}") return Response({ "status": "ERROR", "message": "指定されたイベントが見つかりません" }, status=status.HTTP_404_NOT_FOUND) # 指定クラスのゴール済みチームを取得(スコア降順) teams = Entry.objects.filter( event=event, class_name=class_name, goal_info__isnull=False ).order_by('-goal_info__score') ranking_data = [] for i, team in enumerate(teams): # チームのスタート情報を取得 start_time = None if hasattr(team, 'start_info') and team.start_info: start_time = team.start_info.start_time # チームのゴール情報を取得 goal_time = None score = 0 if hasattr(team, 'goal_info') and team.goal_info: goal_time = team.goal_info.goal_time score = team.goal_info.score or 0 # レース時間を計算 race_time = None if start_time and goal_time: race_seconds = (goal_time - start_time).total_seconds() # 時間:分:秒の形式にフォーマット hours, remainder = divmod(int(race_seconds), 3600) minutes, seconds = divmod(remainder, 60) race_time = f"{hours:02}:{minutes:02}:{seconds:02}" # チェックポイント数を取得 cp_count = 0 try: from rog.models import GpsLog cp_count = GpsLog.objects.filter(entry=team).count() except: pass # ランキングデータに追加 team_data = { "rank": i + 1, # 1-basedのランキング "team_name": team.team_name, "zekken_number": team.zekken_number, "score": score, "race_time": race_time, "start_time": start_time.strftime("%Y-%m-%d %H:%M:%S") if start_time else None, "goal_time": goal_time.strftime("%Y-%m-%d %H:%M:%S") if goal_time else None, "checkpoint_count": cp_count } # オーナー情報があれば追加 if hasattr(team, 'owner') and team.owner: team_data["owner_name"] = team.owner.username team_data["owner_email"] = team.owner.email ranking_data.append(team_data) # 未ゴールチームの数を取得 not_finished_count = Entry.objects.filter( event=event, class_name=class_name, start_info__isnull=False, goal_info__isnull=True ).count() # 登録チーム総数を取得 total_teams = Entry.objects.filter( event=event, class_name=class_name ).count() # イベント情報を取得 event_info = { "event_name": event.event_name, "event_description": getattr(event, 'description', None), "event_date": getattr(event, 'event_date', None) } if hasattr(event, 'event_date') and event.event_date: event_info["event_date"] = event.event_date.strftime("%Y-%m-%d") # 現在の日時 current_time = timezone.now().strftime("%Y-%m-%d %H:%M:%S") return Response({ "status": "OK", "event": event_info, "class_name": class_name, "total_teams": total_teams, "finished_teams": len(ranking_data), "not_finished_teams": not_finished_count, "rankings": ranking_data, "timestamp": current_time }) except Exception as e: logger.error(f"Error in get_ranking: {str(e)}") return Response({ "status": "ERROR", "message": "サーバーエラーが発生しました" }, status=status.HTTP_500_INTERNAL_SERVER_ERROR) # 既存のインポート部分に追加 from rest_framework.decorators import api_view from rest_framework.response import Response from rest_framework import status from rog.models import NewEvent2, Entry import logging from django.db.models import F, Count, Q from django.utils import timezone logger = logging.getLogger(__name__) """ 解説 この実装では以下の処理を行っています: 1.イベントコードのパラメータを受け取ります 2.パラメータが不足している場合はエラーを返します 3.指定されたイベントの存在を確認します 4.イベント内の全クラスを取得します 5.各クラスごとに以下の処理を行います: - ゴール済みチームをスコア降順で取得し、上位3件に絞り込みます - 各チームの基本情報(ランク、名前、ゼッケン番号、スコア、レース時間、チェックポイント数)を収集します - クラスの統計情報(総チーム数、ゴール済みチーム数)を計算します - クラスデータとチームデータを階層化して格納します 6.イベント全体の統計情報も提供します: - 全クラス数 - 全チーム数 - ゴール済みチーム数 - 未ゴールチーム数(スタート済みだがゴールしていないチーム) この実装により、リアルタイムで全クラスのトップ3ランキングを確認できます。 大会のスコアボードやリザルト公開ページなどに利用できます。 1つのリクエストで全クラスの情報が取得できるため、複数のクラスを表示するページで効率的に情報を取得できます。 """ @api_view(['GET']) def all_ranking_top3(request): """ 指定イベントの全クラスにおけるトップ3選手のランキングを取得 パラメータ: - event: イベントコード """ logger.info("all_ranking_top3 called") # リクエストからパラメータを取得 event_code = request.query_params.get('event') logger.debug(f"Parameters: event={event_code}") # パラメータ検証 if not event_code: logger.warning("Missing required event parameter") return Response({ "status": "ERROR", "message": "イベントコードが必要です" }, status=status.HTTP_400_BAD_REQUEST) try: # イベントの存在確認 event = NewEvent2.objects.filter(event_name=event_code).first() if not event: logger.warning(f"Event not found: {event_code}") return Response({ "status": "ERROR", "message": "指定されたイベントが見つかりません" }, status=status.HTTP_404_NOT_FOUND) # イベント内の全クラスを取得 all_classes = Entry.objects.filter( event=event ).values_list('class_name', flat=True).distinct() class_rankings = [] for class_name in all_classes: # 指定クラスのゴール済みチームを取得(スコア降順、上位3件) teams = Entry.objects.filter( event=event, class_name=class_name, goal_info__isnull=False ).order_by('-goal_info__score')[:3] # 上位3件 team_rankings = [] for i, team in enumerate(teams): # チームのスタート情報を取得 start_time = None if hasattr(team, 'start_info') and team.start_info: start_time = team.start_info.start_time # チームのゴール情報を取得 goal_time = None score = 0 if hasattr(team, 'goal_info') and team.goal_info: goal_time = team.goal_info.goal_time score = team.goal_info.score or 0 # レース時間を計算 race_time = None if start_time and goal_time: race_seconds = (goal_time - start_time).total_seconds() # 時間:分:秒の形式にフォーマット hours, remainder = divmod(int(race_seconds), 3600) minutes, seconds = divmod(remainder, 60) race_time = f"{hours:02}:{minutes:02}:{seconds:02}" # チェックポイント数を取得 cp_count = 0 try: from rog.models import GpsLog cp_count = GpsLog.objects.filter(entry=team).count() except: pass # チームデータ team_data = { "rank": i + 1, # 1-basedのランキング "team_name": team.team_name, "zekken_number": team.zekken_number, "score": score, "race_time": race_time, "checkpoint_count": cp_count } team_rankings.append(team_data) # クラスの総チーム数 total_teams_in_class = Entry.objects.filter( event=event, class_name=class_name ).count() # ゴール済みチーム数 finished_teams_in_class = Entry.objects.filter( event=event, class_name=class_name, goal_info__isnull=False ).count() class_data = { "class_name": class_name, "total_teams": total_teams_in_class, "finished_teams": finished_teams_in_class, "top_teams": team_rankings } class_rankings.append(class_data) # イベント情報を取得 event_info = { "event_name": event.event_name, "event_description": getattr(event, 'description', None), "event_date": getattr(event, 'event_date', None) } if hasattr(event, 'event_date') and event.event_date: event_info["event_date"] = event.event_date.strftime("%Y-%m-%d") # 未ゴールチームの数をイベント全体で取得 not_finished_count = Entry.objects.filter( event=event, start_info__isnull=False, goal_info__isnull=True ).count() # ゴール済みチームの数をイベント全体で取得 finished_count = Entry.objects.filter( event=event, goal_info__isnull=False ).count() # 登録チーム総数をイベント全体で取得 total_teams = Entry.objects.filter( event=event ).count() # 現在の日時 current_time = timezone.now().strftime("%Y-%m-%d %H:%M:%S") return Response({ "status": "OK", "event": event_info, "total_classes": len(class_rankings), "total_teams": total_teams, "finished_teams": finished_count, "not_finished_teams": not_finished_count, "rankings_by_class": class_rankings, "timestamp": current_time }) except Exception as e: logger.error(f"Error in all_ranking_top3: {str(e)}") return Response({ "status": "ERROR", "message": "サーバーエラーが発生しました" }, status=status.HTTP_500_INTERNAL_SERVER_ERROR)