From 6ee0f9ea9dea2f46b3d9c79c6a2fd26887aea4e1 Mon Sep 17 00:00:00 2001 From: Martin Putzlocher Date: Fri, 12 Jun 2026 10:38:58 +0000 Subject: [PATCH 1/6] README.md aktualisiert --- README.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 089bb04..79dce62 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,7 +22,7 @@ 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 ``` ### Schritt 1: Die Arbeitsumgebung isolieren (Virtual Environment) @@ -42,9 +45,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. From eac2457a064882afc5c3dd82654310c24947ad1d Mon Sep 17 00:00:00 2001 From: Martin Putzlocher Date: Fri, 12 Jun 2026 10:41:57 +0000 Subject: [PATCH 2/6] README.md aktualisiert --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/README.md b/README.md index 79dce62..79142f4 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,24 @@ pip install django 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. From 5d060587cbe8e83c0fbdccc36cb978e52fa4b66d Mon Sep 17 00:00:00 2001 From: Martin Putzlocher Date: Fri, 12 Jun 2026 12:51:27 +0200 Subject: [PATCH 3/6] =?UTF-8?q?Datenbank=20wieder=20verf=C3=BCgbar=20gemac?= =?UTF-8?q?ht=20f=C3=BCr=20Testdaten?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 - db.sqlite3 | Bin 0 -> 241664 bytes 2 files changed, 1 deletion(-) create mode 100644 db.sqlite3 diff --git a/.gitignore b/.gitignore index 9031276..41e951a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,3 @@ __pycache__/ *.pyc -*.sqlite3 diff --git a/db.sqlite3 b/db.sqlite3 new file mode 100644 index 0000000000000000000000000000000000000000..99587ffd9c4ef5b99d7bcef6693ebd5cdd756152 GIT binary patch literal 241664 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 Xb&m=$Ug5| Date: Thu, 25 Jun 2026 08:59:15 +0200 Subject: [PATCH 4/6] =?UTF-8?q?kleine=20=C3=84nderungen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ns_alter_gericht_time_creation_and_more.py | 38 +++++++++++++++++++ mensa_app/models.py | 4 +- mensa_app/urls.py | 1 + mensa_app/views.py | 1 + 4 files changed, 41 insertions(+), 3 deletions(-) create mode 100644 mensa_app/migrations/0011_alter_person_options_alter_gericht_time_creation_and_more.py 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..fb88a67 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) diff --git a/mensa_app/urls.py b/mensa_app/urls.py index c59a541..0a3ecbe 100644 --- a/mensa_app/urls.py +++ b/mensa_app/urls.py @@ -7,4 +7,5 @@ urlpatterns = [ path('speisekarte/', GerichtListView.as_view(), name='speisekarte'), path('speiseplan/', SpeiseplanView.as_view(), name='speiseplan'), path('bestellungen/summary/', BestellSummaryView.as_view(), name='bestell_summary'), + path('userlist/', {},"" ), ] diff --git a/mensa_app/views.py b/mensa_app/views.py index 662af6f..ba9d79d 100644 --- a/mensa_app/views.py +++ b/mensa_app/views.py @@ -36,6 +36,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) From d7461cb7d2de2e441f75578b1d1052a35f09605a Mon Sep 17 00:00:00 2001 From: Martin Putzlocher Date: Thu, 25 Jun 2026 07:10:32 +0000 Subject: [PATCH 5/6] README.md aktualisiert MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Anleitung für die Entwicklungsarbeit ergänzt --- README.md | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 68 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 79142f4..41e75a7 100644 --- a/README.md +++ b/README.md @@ -140,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 +``` From 40bd15f37829936f5beaa5508f1dc3f252574a24 Mon Sep 17 00:00:00 2001 From: Martin Putzlocher Date: Fri, 26 Jun 2026 09:29:22 +0200 Subject: [PATCH 6/6] =?UTF-8?q?Vorbereitung=20f=C3=BCr=20Erfassung=20neuer?= =?UTF-8?q?=20Gerichte?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mensa_app/forms.py | 33 ++++++++++++ mensa_app/models.py | 1 + .../templates/mensa_app/add_gericht.html | 32 +++++++++++ .../mensa_app/add_gericht_success.html | 29 ++++++++++ mensa_app/urls.py | 17 +++++- mensa_app/views.py | 54 ++++++++++++++----- 6 files changed, 152 insertions(+), 14 deletions(-) create mode 100644 mensa_app/forms.py create mode 100644 mensa_app/templates/mensa_app/add_gericht.html create mode 100644 mensa_app/templates/mensa_app/add_gericht_success.html 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/models.py b/mensa_app/models.py index fb88a67..d99ca4b 100644 --- a/mensa_app/models.py +++ b/mensa_app/models.py @@ -128,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. +

+
+ + +
+ + diff --git a/mensa_app/urls.py b/mensa_app/urls.py index 0a3ecbe..49ea019 100644 --- a/mensa_app/urls.py +++ b/mensa_app/urls.py @@ -7,5 +7,20 @@ urlpatterns = [ path('speisekarte/', GerichtListView.as_view(), name='speisekarte'), path('speiseplan/', SpeiseplanView.as_view(), name='speiseplan'), 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'), ] diff --git a/mensa_app/views.py b/mensa_app/views.py index ba9d79d..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' @@ -51,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' @@ -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 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