3fefc550fe
- Django backend with DRF (clubs, wrestlers, trainers, exercises, templates, trainings, homework, locations, leistungstest) - Next.js 16 frontend with React, Shadcn UI, Tailwind - JWT authentication - Full CRUD for all entities - Calendar view for trainings - Homework management system - Leistungstest tracking
79 lines
2.9 KiB
Python
79 lines
2.9 KiB
Python
from datetime import date, timedelta
|
|
|
|
|
|
def get_date_range(period):
|
|
"""Return start date for period filter, or None for 'all'."""
|
|
today = date.today()
|
|
if period == "month":
|
|
return today.replace(day=1)
|
|
elif period == "3months":
|
|
return today - timedelta(days=90)
|
|
elif period == "year":
|
|
return today.replace(month=1, day=1)
|
|
return None
|
|
|
|
|
|
def get_template_leaderboard(template_id, period="all", limit=10):
|
|
"""Return top wrestlers by score_percent for a template."""
|
|
from .models import LeistungstestResult
|
|
|
|
qs = LeistungstestResult.objects.filter(template_id=template_id)
|
|
|
|
start_date = get_date_range(period)
|
|
if start_date:
|
|
qs = qs.filter(completed_at__date__gte=start_date)
|
|
|
|
qs = qs.select_related('wrestler')
|
|
|
|
results = []
|
|
all_results = list(qs)
|
|
all_results.sort(key=lambda r: (-r.score_percent, r.total_time_seconds))
|
|
for rank, result in enumerate(all_results[:limit], 1):
|
|
results.append({
|
|
'rank': rank,
|
|
'wrestler_id': result.wrestler_id,
|
|
'wrestler_name': str(result.wrestler),
|
|
'score_percent': result.score_percent,
|
|
'total_time_seconds': result.total_time_seconds,
|
|
'completed_at': result.completed_at.date().isoformat() if result.completed_at else None,
|
|
})
|
|
return results
|
|
|
|
|
|
def get_exercise_leaderboard(exercise_id, period="all", limit=10):
|
|
"""Return top wrestlers by best time for an exercise."""
|
|
from .models import LeistungstestResultItem, LeistungstestResult
|
|
from django.db.models import Min
|
|
|
|
start_date = get_date_range(period)
|
|
|
|
qs = LeistungstestResultItem.objects.filter(exercise_id=exercise_id)
|
|
if start_date:
|
|
qs = qs.filter(result__completed_at__date__gte=start_date)
|
|
|
|
# Get best time per wrestler
|
|
best_times = qs.values('result__wrestler__id', 'result__wrestler__first_name', 'result__wrestler__last_name', 'result__completed_at__date')\
|
|
.annotate(best_time=Min('elapsed_seconds'))\
|
|
.order_by('best_time')
|
|
|
|
results = []
|
|
for rank, item in enumerate(best_times[:limit], 1):
|
|
wrestler_name = f"{item['result__wrestler__first_name']} {item['result__wrestler__last_name']}"
|
|
results.append({
|
|
'rank': rank,
|
|
'wrestler_id': item['result__wrestler__id'],
|
|
'wrestler_name': wrestler_name.strip(),
|
|
'best_time_seconds': item['best_time'],
|
|
'completed_at': item['result__completed_at__date'].isoformat() if item['result__completed_at__date'] else None,
|
|
})
|
|
return results
|
|
|
|
|
|
def get_used_exercises():
|
|
"""Return all exercises that have been used in any Leistungstest result."""
|
|
from .models import LeistungstestResultItem
|
|
from exercises.models import Exercise
|
|
|
|
exercise_ids = LeistungstestResultItem.objects.values_list('exercise_id', flat=True).distinct()
|
|
return Exercise.objects.filter(id__in=exercise_ids).order_by('name')
|