Matthias Nagel cb08474301 Fix: EventUpdateView - Formular mit bestehenden Daten vorbefüllen
Behebt einen Fehler in der , bei dem beim Bearbeiten
eines Events (Spiel oder Training) das Formular leer angezeigt wurde
anstatt mit den vorhandenen Daten des Events vorbefüllt zu sein.

Die Ursache war eine Inkonsistenz bei der Übergabe der Modellinstanz:
Die  erhielt ein übergeordnetes -Objekt, während die
 für  oder  eine spezifische Child-Instanz
erwartete.

Änderungen:
- Überschreibung der Methode  in , um die
  korrekte untergeordnete Instanz ( oder ) des Events
  abzurufen und an das Formular zu übergeben.
- Aktualisierung der Methode  in  zur
  Verwendung von  für eine robustere Typüberprüfung des
  Objekts.
2025-11-20 08:54:28 +01:00

194 lines
7.6 KiB
Python

from django.shortcuts import render, get_object_or_404, redirect
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.contrib.auth.decorators import login_required
from django.urls import reverse_lazy
from .models import Event, Training, Game, EventParticipation, GameResult
from .forms import EventForm, TrainingForm, GameForm, OpenGameForm, GameResultForm
from accounts.models import CustomUser # Import CustomUser for manage_participation view
from clubs.models import Team
from django.utils import timezone
import datetime
def select_event_type(request):
return render(request, 'calendars/select_event_type.html')
def get_all_child_teams(parent_team):
"""
Iteratively gets all child teams for a given team.
"""
children = []
teams_to_check = list(parent_team.child_teams.all())
while teams_to_check:
team = teams_to_check.pop(0)
if team not in children:
children.append(team)
teams_to_check.extend(list(team.child_teams.all()))
return children
class ManageableTeamsMixin:
def get_form(self, form_class=None):
form = super().get_form(form_class)
user = self.request.user
if not user.is_superuser:
coached_teams_qs = user.coached_teams.all()
expanded_coached_teams = list(coached_teams_qs)
for team in coached_teams_qs:
expanded_coached_teams.extend(get_all_child_teams(team))
assisted_teams_qs = user.assisted_teams.all()
# Combine and get unique teams
managed_teams_ids = {team.id for team in expanded_coached_teams} | {team.id for team in assisted_teams_qs}
form.fields['team'].queryset = Team.objects.filter(id__in=managed_teams_ids)
return form
class CoachCheckMixin(UserPassesTestMixin):
def test_func(self):
user = self.request.user
if user.is_superuser:
return True
team = self.get_object().team
return user == team.head_coach or user in team.assistant_coaches.all()
class EventCreateView(LoginRequiredMixin, ManageableTeamsMixin, CreateView):
model = Event
form_class = EventForm
template_name = 'calendars/event_form.html'
success_url = reverse_lazy('dashboard')
class TrainingCreateView(LoginRequiredMixin, ManageableTeamsMixin, CreateView):
model = Training
form_class = TrainingForm
template_name = 'calendars/event_form.html'
success_url = reverse_lazy('dashboard')
class GameCreateView(LoginRequiredMixin, ManageableTeamsMixin, CreateView):
model = Game
form_class = GameForm
template_name = 'calendars/event_form.html'
success_url = reverse_lazy('dashboard')
class EventUpdateView(LoginRequiredMixin, CoachCheckMixin, UpdateView):
model = Event
template_name = 'calendars/event_form.html'
success_url = reverse_lazy('dashboard')
def get_object(self, queryset=None):
# Fetch the event and then check if it's a game or training to return the specific instance
obj = super().get_object(queryset)
if hasattr(obj, 'game'):
return obj.game
if hasattr(obj, 'training'):
return obj.training
return obj
def get_form_class(self):
# self.object is now the correct child instance because of the overridden get_object
if isinstance(self.object, Game):
return GameForm
if isinstance(self.object, Training):
return TrainingForm
return EventForm
class EventDeleteView(LoginRequiredMixin, CoachCheckMixin, DeleteView):
model = Event
template_name = 'calendars/event_confirm_delete.html'
success_url = reverse_lazy('dashboard')
@login_required
def manage_participation(request, child_id, event_id, status):
child = get_object_or_404(CustomUser, id=child_id)
event = get_object_or_404(Event, id=event_id)
# Check if the logged-in user is a parent of the child
if request.user not in child.parents.all():
# Handle unauthorized access
return redirect('dashboard')
# Check for parallel events if accepting a support game
if status == 'attending' and hasattr(event, 'game') and child.team in event.game.opened_for_teams.all():
# A game's duration is defined as innings * 20 minutes + 1 hour travel.
# I will assume 9 innings for now.
game_duration = datetime.timedelta(minutes=(9 * 20 + 60))
event_start = event.start_time
event_end = event.start_time + game_duration
parallel_events = Event.objects.filter(
eventparticipation__user=child,
eventparticipation__status='attending'
).exclude(id=event.id)
for pe in parallel_events:
pe_duration = datetime.timedelta(minutes=(9 * 20 + 60)) # Assuming 9 innings for all games
pe_start = pe.start_time
pe_end = pe.start_time + pe_duration
# Check for overlap with a tolerance of +/- 2 hours
if (event_start < pe_end + datetime.timedelta(hours=2) and event_end > pe_start - datetime.timedelta(hours=2)):
# Handle parallel event conflict
return redirect('dashboard') # Or show an error message
participation, created = EventParticipation.objects.get_or_create(user=child, event=event)
participation.status = status
participation.save()
return redirect('dashboard')
@login_required
def open_game(request, game_id):
game = get_object_or_404(Game, id=game_id)
club = game.team.club
# Permission check: only head coach of the team's club can open the game
if not request.user.is_superuser and request.user not in club.administrators.all():
return redirect('dashboard')
if request.method == 'POST':
form = OpenGameForm(request.POST, club=club)
if form.is_valid():
teams = form.cleaned_data['teams']
game.opened_for_teams.add(*teams)
return redirect('dashboard')
else:
form = OpenGameForm(club=club)
return render(request, 'calendars/open_game.html', {'form': form, 'game': game})
@login_required
def record_results(request, game_id):
game = get_object_or_404(Game, id=game_id)
game_result, created = GameResult.objects.get_or_create(game=game)
if request.method == 'POST':
form = GameResultForm(request.POST, game=game, instance=game_result)
if form.is_valid():
inning_results = {}
for i in range(1, game.number_of_innings + 1):
inning_results[f'inning_{i}'] = {
'home': form.cleaned_data.get(f'inning_{i}_home'),
'guest': form.cleaned_data.get(f'inning_{i}_guest'),
}
game_result.inning_results = inning_results
game_result.save()
return redirect('dashboard')
else:
initial_data = {}
if game_result.inning_results:
for inning, scores in game_result.inning_results.items():
initial_data[f'{inning}_home'] = scores.get('home')
initial_data[f'{inning}_guest'] = scores.get('guest')
form = GameResultForm(game=game, instance=game_result, initial=initial_data)
form_fields_by_inning = []
for i in range(1, game.number_of_innings + 1):
form_fields_by_inning.append({
'inning': i,
'home': form[f'inning_{i}_home'],
'guest': form[f'inning_{i}_guest'],
})
return render(request, 'calendars/record_results.html', {'form': form, 'game': game, 'form_fields_by_inning': form_fields_by_inning})