Initial commit: WrestleDesk full project
- 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
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
from rest_framework import viewsets
|
||||
from rest_framework.decorators import api_view, permission_classes
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
from rest_framework.response import Response
|
||||
from django.db.models import Count, Avg, Sum, F
|
||||
from django.db.models.functions import Coalesce
|
||||
from datetime import datetime, timedelta
|
||||
from .models import TrainingLogEntry
|
||||
from .serializers import TrainingLogEntrySerializer
|
||||
from wrestlers.models import Wrestler
|
||||
|
||||
|
||||
class TrainingLogEntryViewSet(viewsets.ModelViewSet):
|
||||
permission_classes = [IsAuthenticated]
|
||||
serializer_class = TrainingLogEntrySerializer
|
||||
|
||||
def get_queryset(self):
|
||||
queryset = TrainingLogEntry.objects.all()
|
||||
wrestler = self.request.query_params.get('wrestler')
|
||||
exercise = self.request.query_params.get('exercise')
|
||||
date_from = self.request.query_params.get('date_from')
|
||||
date_to = self.request.query_params.get('date_to')
|
||||
|
||||
if wrestler:
|
||||
queryset = queryset.filter(wrestler=wrestler)
|
||||
if exercise:
|
||||
queryset = queryset.filter(exercise=exercise)
|
||||
if date_from:
|
||||
queryset = queryset.filter(logged_at__date__gte=date_from)
|
||||
if date_to:
|
||||
queryset = queryset.filter(logged_at__date__lte=date_to)
|
||||
|
||||
return queryset.select_related('wrestler', 'exercise', 'training')
|
||||
|
||||
|
||||
@api_view(['GET'])
|
||||
@permission_classes([IsAuthenticated])
|
||||
def training_log_stats(request):
|
||||
wrestler_id = request.query_params.get('wrestler')
|
||||
today = datetime.now().date()
|
||||
week_start = today - timedelta(days=today.weekday())
|
||||
|
||||
queryset = TrainingLogEntry.objects.all()
|
||||
if wrestler_id:
|
||||
queryset = queryset.filter(wrestler=wrestler_id)
|
||||
|
||||
total_entries = queryset.count()
|
||||
unique_exercises = queryset.values('exercise').distinct().count()
|
||||
total_reps = queryset.aggregate(total=Coalesce(Sum(F('reps') * F('sets')), 0))['total'] or 0
|
||||
avg_sets = queryset.aggregate(avg=Avg('sets'))['avg'] or 0
|
||||
avg_rating = queryset.aggregate(avg=Avg('rating'))['avg'] or 0
|
||||
this_week = queryset.filter(logged_at__date__gte=week_start).count()
|
||||
|
||||
top_exercises = queryset.values('exercise__name').annotate(
|
||||
count=Count('id')
|
||||
).order_by('-count')[:5]
|
||||
|
||||
progress = {}
|
||||
exercises = queryset.values('exercise', 'exercise__name').distinct()
|
||||
for ex in exercises:
|
||||
ex_id = ex['exercise']
|
||||
entries = queryset.filter(exercise=ex_id).order_by('logged_at')
|
||||
if entries.count() >= 2:
|
||||
first_reps = entries.first().reps * entries.first().sets
|
||||
last_reps = entries.last().reps * entries.last().sets
|
||||
if first_reps > 0:
|
||||
change = ((last_reps - first_reps) / first_reps) * 100
|
||||
progress[ex['exercise__name']] = {
|
||||
'before': first_reps,
|
||||
'after': last_reps,
|
||||
'change_percent': round(change, 1)
|
||||
}
|
||||
|
||||
return Response({
|
||||
'total_entries': total_entries,
|
||||
'unique_exercises': unique_exercises,
|
||||
'total_reps': total_reps,
|
||||
'avg_sets': round(avg_sets, 1),
|
||||
'avg_rating': round(avg_rating, 1),
|
||||
'this_week': this_week,
|
||||
'top_exercises': [{'name': e['exercise__name'], 'count': e['count']} for e in top_exercises],
|
||||
'progress': progress,
|
||||
})
|
||||
|
||||
|
||||
@api_view(['GET'])
|
||||
@permission_classes([IsAuthenticated])
|
||||
def training_log_compare(request):
|
||||
wrestler1_id = request.query_params.get('wrestler1')
|
||||
wrestler2_id = request.query_params.get('wrestler2')
|
||||
|
||||
if not wrestler1_id or not wrestler2_id:
|
||||
return Response({'error': 'Both wrestler1 and wrestler2 required'}, status=400)
|
||||
|
||||
wrestler1 = Wrestler.objects.get(id=wrestler1_id)
|
||||
wrestler2 = Wrestler.objects.get(id=wrestler2_id)
|
||||
|
||||
entries1 = TrainingLogEntry.objects.filter(wrestler=wrestler1)
|
||||
entries2 = TrainingLogEntry.objects.filter(wrestler=wrestler2)
|
||||
|
||||
exercises1 = entries1.values('exercise', 'exercise__name').distinct()
|
||||
exercises2 = entries2.values('exercise', 'exercise__name').distinct()
|
||||
common_exercises = set(e['exercise'] for e in exercises1) & set(e['exercise'] for e in exercises2)
|
||||
|
||||
comparison = []
|
||||
for ex_id in common_exercises:
|
||||
ex_name = entries1.filter(exercise=ex_id).first().exercise.name
|
||||
avg1 = entries1.filter(exercise=ex_id).aggregate(avg=Avg(F('reps') * F('sets')))['avg'] or 0
|
||||
avg2 = entries2.filter(exercise=ex_id).aggregate(avg=Avg(F('reps') * F('sets')))['avg'] or 0
|
||||
comparison.append({
|
||||
'exercise': ex_name,
|
||||
'wrestler1_avg': round(avg1, 1),
|
||||
'wrestler2_avg': round(avg2, 1)
|
||||
})
|
||||
|
||||
return Response({
|
||||
'wrestler1': {'id': wrestler1.id, 'name': str(wrestler1)},
|
||||
'wrestler2': {'id': wrestler2.id, 'name': str(wrestler2)},
|
||||
'exercises': comparison
|
||||
})
|
||||
Reference in New Issue
Block a user