initial setting at 20-Aug-2025

This commit is contained in:
2025-08-20 19:15:19 +09:00
parent eab529bd3b
commit 1ba305641e
149 changed files with 170449 additions and 1802 deletions

374
rog/views_apis/api_ranking.py Executable file
View File

@ -0,0 +1,374 @@
# 既存のインポート部分に追加
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)