diff --git a/.gitignore b/.gitignore index 9031276..41e951a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ __pycache__/ *.pyc -*.sqlite3 diff --git a/README.md b/README.md index 089bb04..41e75a7 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,15 @@ Muster-Implementation durch die Lehrkraft in python3 mit Django ## To get started +## Vorbereitung der virtuellen Entwicklungsumgebung + +in einem Projekt-Vezeichnis über dem eigentlichen SGTMensa-Projekt-Ordner + ```bash -cd SGTMensa python3 -m venv .venv source .venv/bin/activate pip install django -django-admin startproject mensa-core . +pip install pillow ``` Falls eine fish-Shell vorliegt: @@ -19,9 +22,27 @@ Falls eine fish-Shell vorliegt: python3 -m venv .venv source .venv/bin/activate.fish pip install django -django-admin startproject mensa-core . +pip install pillow ``` +## Klonen des eigentlichen Projekts + +```bash +git clone https://git.sgtlernen.de/mputzlocher/SGTMensa.git +``` + +## Starten des Servers + +```bash +cd SGTMensa +python manage.py runserver +``` + + +--- + +# Erweiterte Erklärung einzelner Schritte + ### Schritt 1: Die Arbeitsumgebung isolieren (Virtual Environment) Bevor du auch nur eine Zeile Code schreibst, erstelle eine eigene Umgebung. Das verhindert, dass sich verschiedene Projekte auf deinem Rechner gegenseitig stören. @@ -42,9 +63,10 @@ Installiere nur das Nötigste. Für den Start reicht Django. ```bash pip install django +pip install pillow ``` -### Schritt 3: Das Projekt initialisieren +### Schritt 3: Das Projekt initialisieren (nur einmalig, beim ersten Start des Projekts) Erstelle die Struktur eines Django-Projekts. @@ -118,4 +140,71 @@ python manage.py runserver -Öffne deinen Browser unter `http://127.0.0.1:8000/admin`. Logge dich mit deinem Superuser ein. **Herzlichen Glückwunsch!** Du hast eine voll funktionsfähige Web-Anwendung, mit der du bereits Speisepläne und Bestellungen in einer Datenbank verwalten kannst. \ No newline at end of file +Öffne deinen Browser unter `http://127.0.0.1:8000/admin`. Logge dich mit deinem Superuser ein. **Herzlichen Glückwunsch!** Du hast eine voll funktionsfähige Web-Anwendung, mit der du bereits Speisepläne und Bestellungen in einer Datenbank verwalten kannst. + + +### Schritt 9: Eigentliche Entwicklungsarbeit + +Folgende Befehle werden nacheinander ausgeführt: + +#### Eigenen Projektbaum auf dem lokalen Rechen auf den aktuellen Stand bringen + +Öffne ein Terminal und navigiere in das Projektverzeichnis, das bereits über `git clone` abgeholt worden ist. + +zum Beispiel: +```bash +cd ~/projects/SGTMensa +``` + +Hole den aktuellen Stand ab: +```bash +git pull +``` + +Aktiviere die virtuelle Entwicklungsumgebung (falls noch nicht geschehen): +```bash +source .venv/bin/activate +``` + +Führe notwendige Migrationen der bestehenden Datenbank aus: +```bash +python manage.py makemigrations +python manage.py migrate +``` + +Starte den Server des Projekts: +```bash +python manage.py runserver +``` +Jetzt bist Du startklar für die Entwicklungsarbeit und solltest den aktuellen Stand im Browser unter `http://localhost:8000/` abrufen können. + +#### Änderungen vornehmen + +Django erkennt selbstständig Veränderungen am Quellcode und startet den Webserver neu. Achte auf Fehlermeldungen! + +#### Änderungen wieder auf den git-Server einspielen + +Nach einem Entwicklungsschritt solltest Du Deine Änderungen von Deinem lokalen Rechner wieder auf den git-Server hochladen, +damit Dein Team auch sieht, was Du gemacht hast, und damit Deine Ergänzungen und Änderungen wieder in den gemeinsamen +Code integriert werden können. + +Nachsehen der Änderungen: +```bash +git status +``` +Dies zeigt alle veränderten Dateien an. + +Veränderte Dateien ins Änderungspaket aufnehmen: +```bash +git add . +``` + +Veränderungen bestätigen und beschreiben: +```bash +git commit -m "Deine sinnvolle Beschreibung der Änderung in wenigen Worten" +``` + +Veränderungen auf den git-Server hochladen: +```bash +git push +``` diff --git a/db.sqlite3 b/db.sqlite3 new file mode 100644 index 0000000..99587ff Binary files /dev/null and b/db.sqlite3 differ diff --git a/mensa_app/forms.py b/mensa_app/forms.py new file mode 100644 index 0000000..d9bcac4 --- /dev/null +++ b/mensa_app/forms.py @@ -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 diff --git a/mensa_app/migrations/0011_alter_person_options_alter_gericht_time_creation_and_more.py b/mensa_app/migrations/0011_alter_person_options_alter_gericht_time_creation_and_more.py new file mode 100644 index 0000000..81d30d5 --- /dev/null +++ b/mensa_app/migrations/0011_alter_person_options_alter_gericht_time_creation_and_more.py @@ -0,0 +1,38 @@ +# Generated by Django 5.2.15 on 2026-06-12 10:50 + +import datetime +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('mensa_app', '0010_merge_20260612_0913'), + ] + + operations = [ + migrations.AlterModelOptions( + name='person', + options={}, + ), + migrations.AlterField( + model_name='gericht', + name='time_creation', + field=models.TimeField(default=datetime.datetime(2026, 6, 12, 10, 50, 49, 206132)), + ), + migrations.AlterField( + model_name='gericht', + name='time_last_change', + field=models.TimeField(default=datetime.datetime(2026, 6, 12, 10, 50, 49, 206132)), + ), + migrations.AlterField( + model_name='gerichtbild', + name='id', + field=models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), + ), + migrations.AlterField( + model_name='person', + name='rolle', + field=models.CharField(choices=[('schueler', 'Schüler'), ('eltern', 'Eltern'), ('lehrer', 'Lehrer'), ('mitarbeiter', 'Mensa-Mitarbeiter'), ('chef', 'Mensa-Leitung')], max_length=20), + ), + ] diff --git a/mensa_app/models.py b/mensa_app/models.py index 88062d2..d99ca4b 100644 --- a/mensa_app/models.py +++ b/mensa_app/models.py @@ -1,10 +1,8 @@ +import os from django.db import models from django.contrib.auth.models import User from django.utils import timezone import datetime - -import os -from django.db import models from django.core.exceptions import ValidationError from django.core.validators import FileExtensionValidator # Pillow ist für die Bildbearbeitung zuständig (installiere per pip install pillow) @@ -130,6 +128,7 @@ class Gericht(models.Model): ) ist_vegetarisch = 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="") preis = models.DecimalField(max_digits=5, decimal_places=2, default=0.00) diff --git a/mensa_app/templates/mensa_app/add_gericht.html b/mensa_app/templates/mensa_app/add_gericht.html new file mode 100644 index 0000000..f89c48e --- /dev/null +++ b/mensa_app/templates/mensa_app/add_gericht.html @@ -0,0 +1,32 @@ + + + + + + +
+

Neue Speiseart hinzufügen

+ + {# !!! KRITISCH WICHTIG: enctype muss für Dateiuploads stehen !!! #} +
+ {% csrf_token %} + + + {# Man kann die komplexe Struktur durch eine einfache Schleife ersetzen #} + {% for field in form %} +
+ + {{ field }} + + + {% if field.errors %} +

{{ field.errors }}

+ {% endif %} +
+ {% endfor %} + + +
+
+ + diff --git a/mensa_app/templates/mensa_app/add_gericht_success.html b/mensa_app/templates/mensa_app/add_gericht_success.html new file mode 100644 index 0000000..72f716c --- /dev/null +++ b/mensa_app/templates/mensa_app/add_gericht_success.html @@ -0,0 +1,29 @@ + + + + + Erfolg + + + + +
+
+

🎉 Erfolgreich hinzugefügt! 🎉

+

+ Das Gericht {{ objekt_name }} wurde erfolgreich in das Menüsystem übernommen. +

+

+ Du kannst nun die Details überprüfen und weitere Gerichte hinzufügen. +

+
+ +
+ + + ← Zurück zur Speisekarte & Verwalten + +
+
+ + diff --git a/mensa_app/urls.py b/mensa_app/urls.py index c59a541..49ea019 100644 --- a/mensa_app/urls.py +++ b/mensa_app/urls.py @@ -8,3 +8,19 @@ urlpatterns = [ path('speiseplan/', SpeiseplanView.as_view(), name='speiseplan'), path('bestellungen/summary/', BestellSummaryView.as_view(), name='bestell_summary'), ] + +# 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'), +] diff --git a/mensa_app/views.py b/mensa_app/views.py index 662af6f..f5b1658 100644 --- a/mensa_app/views.py +++ b/mensa_app/views.py @@ -1,18 +1,20 @@ +# views.py +from django.db.models import Count, Sum 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): model = Gericht template_name = 'mensa_app/gericht_liste.html' # Der Pfad zum Template 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): template_name = 'mensa_app/speiseplan.html' @@ -36,6 +38,7 @@ class SpeiseplanView(TemplateView): context['target_date'] = target_date context['menues_day'] = Menue.objects.filter(tag__datum=target_date) + # 3. Dauerangebote laden (unabhängig vom Tag) context['dauerangebote'] = Gericht.objects.filter(ist_dauerangebot=True) @@ -50,12 +53,6 @@ class SpeiseplanView(TemplateView): 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): template_name = 'mensa_app/bestell_summary.html' @@ -99,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 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