@efix: Du Benutzt `Service`-Objekte falsch. Auf die Klasse gehören die `Form`-Attribute. Und da dann auch nicht alles als `forms.CharField()`. Der Witz davon ist ja gerade die Validierung und ”Säuberung” der ”Argumente”. Das man da nicht mehr selbst Zeichenketten in Datums- und Zeit-Objekte umwandeln muss.
Und das dürfte auch der Grund für den `KeyError` sein, denn wo sollen die Schlüssel in `self.cleaned_data` auch her kommen wenn die nicht entsprechend als `form`-Felder erstellt wurden‽
Die `process()`-Methode kopiert sinnlos Daten von einem Wörterbuch in ein anderes. Warum? Zudem ist das auch noch kaputt, weil das Ziel ein Klassenattribut ist, also eine globale Variable. Das fällt bei Nebenläufigkeit dann auf die Nase. Und das ist recht wahrscheinlich, weil es sich um eine Webanwendung handelt, bei der mehrere Threads anfragen beantworten können.
Und dann wird aus `process()` die Methode aufgerufen die eigentlich das macht was in `process()` stehen sollte. Das hatte ich in einem anderen Thema ja schon mal geschrieben: das gehört in `process()`. Diese `Service`-Objekte sind eigentlich umständlich geschriebene Funktionen. Man kann die `process()`-Methode hier als `__call__()`-Implementierung sehen. Der Name der ”Funktion” ist der Klassenname. Man führt hier ja letztlich immer die Klasse aus, in dem man die Klassenmethode `execute()` aufruft.
In der `start()`-Funktion ist `uid` extrem sinnfrei. Das ist ein Wörterbuch mit genau einem Schlüssel/Wert-Paar wobei das Wörterbuch selbst nirgends verwendet wird. Es wird immer nur der eine Wert da raus geholt und verwendet. Warum steckt das dann in einem Wörterbuch? Die ``**``-Magie beim Argument von `start()` ist schon unsinnig.
In der Funktion wird die gleiche Information mal als "user", mal als "uid", und mal als "user_id" bezeichnet. Das ist verwirrend und Du solltest Dich auf *eine* Benennung im ganzen Programm festlegen. Wobei alle drei IMHO nicht gut sind, denn wenn da "id" im Namen vorkommt, im Kontext von Datenbanken, dann erwartet der Leser eine Zahl und keine Zeichenkette. Und bei `user` würde man ein Benuter-Objekt erwarten. Also wäre da `username` vielleicht passend.
Hier wäre dann die komplette Service-Klasse, ohne da noch zusätzliche Methoden zu definieren, denn auch da hat man ja das Problem, dass die mit den Attributen/Methoden von `Service` und `Form` kollidieren können:
Code: Alles auswählen
class InsertBookingService(Service):
username = forms.CharField()
date = forms.DateField()
time = forms.TimeField()
veg = forms.CharField()
def process(self):
start_timestamp = DateTime.combine(
self.cleaned_data["date"], self.cleaned_data["time"]
).timestamp()
return Booking(
username=self.cleaned_data["username"],
start=start_timestamp,
end=start_timestamp + 2700,
veg=self.cleaned_data["veg"],
).save()
Und die `start()`:
Code: Alles auswählen
def start(request, username):
if request.method == "POST":
data = dict(request.POST)
InsertBookingService.execute(
{
"username": username,
"date": data["date"],
"time": data["time"],
"veg": data["veg"],
}
)
return redirect("/start/" + username)
return render(
request,
"index.html",
{
"data": json.dumps(
GetBookingService.execute({"username": username})
)
},
)
Hier ist das hart kodierte "/start/" unschön.
Ich erwähnte im anderen Thema ja schon mal wie sinnlos ich diese `Service`-Objekte finde. Das würde noch mal deutlicher wenn man hier Django-Forms benutzen würde. Das ist dann eine grosse sinnlose herumkopiererei von Werten aus Wörterbüchern und mehrfache Validierung der gleichen Werte.
Ohne diese komischen Servie-Objekte könnte das ungefähr so aussehen:
Code: Alles auswählen
class InsertBookingForm(forms.Form):
date = forms.DateField()
time = forms.TimeField()
veg = forms.CharField()
def get_booking(username):
...
def insert_booking(username, date, time, veg):
start_timestamp = DateTime.combine(date, time).timestamp()
return Booking(
username=username,
start=start_timestamp,
end=start_timestamp + 2700,
veg=veg,
).save()
def start(request, username):
form = InsertBookingForm()
if request.method == "POST":
form = InsertBookingForm(request.POST)
if form.is_valid():
insert_booking(
username,
form.cleaned_data["date"],
form.cleaned_data["time"],
form.cleaned_data["veg"],
)
else:
...
return redirect("/start/" + username)
return render(
request,
"index.html",
{"data": json.dumps(get_booking(username)), "form": form},
)