Branch gui-dev auf aktuellen Stand bringen #10

Merged
mputzlocher merged 7 commits from main into gui-dev 2026-06-26 07:33:27 +00:00
6 changed files with 152 additions and 14 deletions
Showing only changes of commit 40bd15f378 - Show all commits
+33
View File
@@ -0,0 +1,33 @@
# forms.py
from django import forms
from .models import Gericht
# Importiere alle Modelle, die für das Formular relevant sind
from .models import Kategorie
class GerichtForm(forms.ModelForm):
"""Definiert die Struktur und Validierungsregeln für das Gericht-Modell."""
class Meta:
model = Gericht
fields = [
'name',
'kategorie',
'preis',
'ist_vegetarisch',
'ist_allergene_frei',
'allergene',
'beschreibung', # Neues Feld für Zutaten/Rohstoffe
'bilder', # Das Bild-Feld
'ist_dauerangebot'
]
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Wir können hier zusätzliche Validierungen oder Widgets einbinden
# Beispiel: Erzwinge das Betreten der Kategorie-Auswahl
self.fields['kategorie'].required = True
# Hier könntest du auch einen Fallback für den Preis hinzufügen, falls er nicht gesetzt ist
if 'initial' in kwargs: # Wird bei GET-Requests genutzt
self.initial['preis'] = 0.00
+1
View File
@@ -128,6 +128,7 @@ class Gericht(models.Model):
) )
ist_vegetarisch = models.BooleanField(default=False) ist_vegetarisch = models.BooleanField(default=False)
ist_allergene_frei = models.BooleanField(default=False) ist_allergene_frei = models.BooleanField(default=False)
beschreibung = models.TextField(blank=True, null=True) # Zutaten/Rohstoffe Beschreibung (Textfeld für V1)
allergene = models.TextField(blank=True, default="") allergene = models.TextField(blank=True, default="")
preis = models.DecimalField(max_digits=5, decimal_places=2, default=0.00) preis = models.DecimalField(max_digits=5, decimal_places=2, default=0.00)
@@ -0,0 +1,32 @@
<!DOCTYPE html>
<html lang="de">
<head>
<!-- (Standard Head und Bootstrap CDN einbinden) -->
</head>
<body class="bg-light">
<div class="container mt-5">
<h1>Neue Speiseart hinzufügen</h1>
{# !!! KRITISCH WICHTIG: enctype muss für Dateiuploads stehen !!! #}
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<!-- Der Standardway, alle Felder mit Bootstrap zu stylen (für Anfänger am besten) -->
{# Man kann die komplexe Struktur durch eine einfache Schleife ersetzen #}
{% for field in form %}
<div class="mb-3">
<label for="{{ field.id_for_label }}" class="form-label">{{ field.label }}</label>
{{ field }}
<!-- Fehlerhinweis des Feldes wird hier automatisch gerendert -->
{% if field.errors %}
<p class="text-danger small mt-1">{{ field.errors }}</p>
{% endif %}
</div>
{% endfor %}
<button type="submit" class="btn btn-success mt-4">Gericht Speichern & Veröffentlichen</button>
</form>
</div>
</body>
</html>
@@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>Erfolg</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container mt-5">
<div class="alert alert-success shadow p-5 text-center">
<h2 class="mb-3">🎉 Erfolgreich hinzugefügt! 🎉</h2>
<p class="lead">
Das Gericht <strong>{{ objekt_name }}</strong> wurde erfolgreich in das Menüsystem übernommen.
</p>
<p>
Du kannst nun die Details überprüfen und weitere Gerichte hinzufügen.
</p>
</div>
<div class="mt-4 text-center">
<!-- Der wichtigste Button, der zum Hauptbereichen zurückführt -->
<a href="{% url 'speisekarte' %}" class="btn btn-primary btn-lg">
&larr; Zurück zur Speisekarte &amp; Verwalten
</a>
</div>
</div>
</body>
</html>
+16 -1
View File
@@ -7,5 +7,20 @@ urlpatterns = [
path('speisekarte/', GerichtListView.as_view(), name='speisekarte'), path('speisekarte/', GerichtListView.as_view(), name='speisekarte'),
path('speiseplan/', SpeiseplanView.as_view(), name='speiseplan'), path('speiseplan/', SpeiseplanView.as_view(), name='speiseplan'),
path('bestellungen/summary/', BestellSummaryView.as_view(), name='bestell_summary'), path('bestellungen/summary/', BestellSummaryView.as_view(), name='bestell_summary'),
path('userlist/', {},"" ), ]
# ACHTUNG: Hier benötigen wir jetzt eine separate View für die Erfolgsmeldung!
# Wir nutzen hierfür ein sehr einfaches TemplateView.
from django.views.generic import TemplateView # Muss oben importiert werden
from .models import Gericht
class ErfolgTemplateView(TemplateView):
"""Zeigt einfach nur die Bestätigung an."""
template_name = 'mensa_app/add_gericht_success.html'
urlpatterns += [
# ... (vorherige Pfade bleiben) ...
path('gerichte/neu/', GerichtCreateView.as_view(), name='add_gericht'),
# NEU: Erfolgsmeldung nach erfolgreichem POST/redirect
path('erfolg/', ErfolgTemplateView.as_view(), name='success_message'),
] ]
+41 -13
View File
@@ -1,18 +1,20 @@
# views.py
from django.db.models import Count, Sum
from django.shortcuts import render from django.shortcuts import render
from django.utils import timezone
from datetime import datetime
from django.views.generic import ListView, TemplateView
from django.views.generic.edit import CreateView
from django.shortcuts import redirect # Importiere die Redirect-Funktion
from .forms import GerichtForm # Importiere dein neues Formular
from .models import Gericht, Menue, SpeiseplanTag, Bestellung
# Create your views here.
from django.views.generic import ListView
from .models import Gericht
class GerichtListView(ListView): class GerichtListView(ListView):
model = Gericht model = Gericht
template_name = 'mensa_app/gericht_liste.html' # Der Pfad zum Template template_name = 'mensa_app/gericht_liste.html' # Der Pfad zum Template
context_object_name = 'alle_gerichte' # Der Name, den wir im Template nutzen context_object_name = 'alle_gerichte' # Der Name, den wir im Template nutzen
from django.views.generic import TemplateView
from django.utils import timezone
from datetime import datetime
from .models import Menue, Gericht, SpeiseplanTag
class SpeiseplanView(TemplateView): class SpeiseplanView(TemplateView):
template_name = 'mensa_app/speiseplan.html' template_name = 'mensa_app/speiseplan.html'
@@ -51,12 +53,6 @@ class SpeiseplanView(TemplateView):
return context return context
from django.views.generic import TemplateView
from django.utils import timezone
from django.db.models import Count, Sum
from datetime import datetime
from .models import Bestellung, SpeiseplanTag, Gericht, Menue
class BestellSummaryView(TemplateView): class BestellSummaryView(TemplateView):
template_name = 'mensa_app/bestell_summary.html' template_name = 'mensa_app/bestell_summary.html'
@@ -100,3 +96,35 @@ class BestellSummaryView(TemplateView):
context['total_umsatz'] = Bestellung.objects.filter(menue__tag__datum=target_date).aggregate(Sum('menue__preis'))['menue__preis__sum'] or 0 context['total_umsatz'] = Bestellung.objects.filter(menue__tag__datum=target_date).aggregate(Sum('menue__preis'))['menue__preis__sum'] or 0
return context return context
class GerichtCreateView(CreateView):
"""
View zur Erstellung eines neuen Gerichts.
Nutzt das benutzerdefinierte GerichtForm für die gesamte Steuerung.
"""
model = Gericht
form_class = GerichtForm # Verwendet unser Custom-Formular
template_name = 'mensa_app/add_gericht.html'
def get_success_url(self):
# Die Methode wird ausgeführt, nachdem die View erfolgreich ist
objekt = self.object # Gibt uns das gerade gespeicherte Objekt zurück
return reverse('speisekarte')
def form_valid(self, form):
"""
Übersteuert die Standard-Logik:
1. Speichert zuerst das Gericht (über super()).
2. Leitet danach auf ein success/confirmation Pattern um.
"""
super().form_valid() # Das eigentliche Speichern des Objekts
# Hier ist der Haken an Django: Die View wird beim Erfolg automatisch weitergeleitet.
# Wir verwenden einen kleinen Trick, damit wir den Namen im Kontext haben.
return redirect('success_nach_gerichterstellung') # Leiten auf eine temporäre URL um
# Optional: Setzen des initialen Datenzustands (z.B. Datum, falls relevant)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
return context