Files
Andrej Spielmann 3fefc550fe 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
2026-03-26 13:24:57 +01:00

189 lines
7.6 KiB
Python

from django.db import models
class Homework(models.Model):
title = models.CharField(max_length=200)
description = models.TextField(blank=True)
club = models.ForeignKey('clubs.Club', on_delete=models.CASCADE, related_name='homework_templates', null=True, blank=True)
due_date = models.DateField(null=True, blank=True)
is_active = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
ordering = ['-created_at']
indexes = [
models.Index(fields=['due_date']),
models.Index(fields=['club']),
]
def __str__(self):
return self.title
class HomeworkExerciseItem(models.Model):
homework = models.ForeignKey(Homework, on_delete=models.CASCADE, related_name='exercise_items')
exercise = models.ForeignKey('exercises.Exercise', on_delete=models.CASCADE, related_name='homework_items')
reps = models.PositiveIntegerField(null=True, blank=True)
time_minutes = models.PositiveIntegerField(null=True, blank=True)
order = models.IntegerField(default=0)
class Meta:
ordering = ['homework', 'order']
unique_together = ['homework', 'exercise']
def __str__(self):
return f"{self.homework.title} - {self.exercise.name}"
class HomeworkAssignment(models.Model):
homework = models.ForeignKey(Homework, on_delete=models.CASCADE, related_name='assignments')
wrestler = models.ForeignKey('wrestlers.Wrestler', on_delete=models.CASCADE, related_name='homework_assignments')
club = models.ForeignKey('clubs.Club', on_delete=models.CASCADE, related_name='homework_assignments', null=True, blank=True)
due_date = models.DateField(null=True, blank=True)
notes = models.TextField(blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
unique_together = ['homework', 'wrestler']
ordering = ['-created_at']
indexes = [
models.Index(fields=['wrestler']),
models.Index(fields=['due_date']),
]
def __str__(self):
return f"{self.wrestler} - {self.homework.title}"
def clean(self):
from wrestlers.models import Wrestler
if self.wrestler and self.homework and self.wrestler.club_id != self.homework.club_id:
from django.core.exceptions import ValidationError
raise ValidationError('Wrestler must belong to the same club as the homework')
@property
def is_completed(self):
items = self.items.all()
if not items.exists():
return False
return all(item.is_completed for item in items)
@property
def completion_date(self):
if self.is_completed:
return self.items.filter(is_completed=True).order_by('-completion_date').first().completion_date
return None
class HomeworkAssignmentItem(models.Model):
assignment = models.ForeignKey(HomeworkAssignment, on_delete=models.CASCADE, related_name='items')
exercise = models.ForeignKey('exercises.Exercise', on_delete=models.CASCADE, related_name='assignment_items')
is_completed = models.BooleanField(default=False)
completion_date = models.DateField(null=True, blank=True)
class Meta:
unique_together = ['assignment', 'exercise']
indexes = [
models.Index(fields=['assignment', 'is_completed']),
models.Index(fields=['completion_date']),
]
def __str__(self):
status = "" if self.is_completed else ""
return f"{self.assignment} - {self.exercise.name} {status}"
class HomeworkStatus(models.Model):
homework = models.ForeignKey(Homework, on_delete=models.CASCADE, related_name='statuses')
wrestler = models.ForeignKey('wrestlers.Wrestler', on_delete=models.CASCADE, related_name='homework_statuses')
is_completed = models.BooleanField(default=False)
completion_date = models.DateField(null=True, blank=True)
notes = models.TextField(blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
unique_together = ['homework', 'wrestler']
def __str__(self):
status = "" if self.is_completed else ""
return f"{self.wrestler} - {self.homework.title} {status}"
# NEUES SYSTEM: Training-basierte Homework
# Jeder Wrestler bekommt individuelle Übungen zugewiesen
class TrainingHomeworkAssignment(models.Model):
"""A homework assignment for a specific wrestler in a specific training"""
training = models.ForeignKey('trainings.Training', on_delete=models.CASCADE, related_name='homework_assignments', default=1)
wrestler = models.ForeignKey('wrestlers.Wrestler', on_delete=models.CASCADE, related_name='training_homework_assignments')
club = models.ForeignKey('clubs.Club', on_delete=models.CASCADE, related_name='training_homework_assignments', null=True, blank=True)
notes = models.TextField(blank=True)
is_completed = models.BooleanField(default=False)
completion_date = models.DateField(null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
unique_together = ['training', 'wrestler']
ordering = ['-created_at']
indexes = [
models.Index(fields=['training']),
models.Index(fields=['wrestler']),
models.Index(fields=['is_completed']),
models.Index(fields=['club']),
]
def __str__(self):
return f"{self.wrestler} - Training {self.training_id}"
class TrainingHomeworkExerciseItem(models.Model):
"""Individual exercises assigned to a specific wrestler (NOT shared)"""
assignment = models.ForeignKey(TrainingHomeworkAssignment, on_delete=models.CASCADE, related_name='exercises')
exercise = models.ForeignKey('exercises.Exercise', on_delete=models.CASCADE, related_name='training_homework_exercises')
reps = models.PositiveIntegerField(null=True, blank=True)
time_minutes = models.PositiveIntegerField(null=True, blank=True)
order = models.IntegerField(default=0)
is_completed = models.BooleanField(default=False)
class Meta:
ordering = ['assignment', 'order']
def __str__(self):
return f"{self.assignment} - {self.exercise.name}"
# ALTES SYSTEM (für Rückwärtskompatibilität - wird nicht mehr verwendet)
class TrainingHomework(models.Model):
"""DEPRECATED: Each wrestler now has individual assignments"""
training = models.ForeignKey('trainings.Training', on_delete=models.CASCADE, related_name='homework_legacy')
created_at = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['-created_at']
indexes = [
models.Index(fields=['training']),
]
def __str__(self):
return f"Homework for Training {self.training_id}"
class TrainingHomeworkExercise(models.Model):
"""DEPRECATED: Exercises are now per-assignment"""
training_homework = models.ForeignKey(TrainingHomework, on_delete=models.CASCADE, related_name='exercises')
exercise = models.ForeignKey('exercises.Exercise', on_delete=models.CASCADE, related_name='training_homework_items')
reps = models.PositiveIntegerField(null=True, blank=True)
time_minutes = models.PositiveIntegerField(null=True, blank=True)
order = models.IntegerField(default=0)
class Meta:
ordering = ['training_homework', 'order']
unique_together = ['training_homework', 'exercise']
def __str__(self):
return f"{self.training_homework} - {self.exercise.name}"