Hallo,
um ein bestimmtes Model zu editieren benutze ich eine Formularklasse, die von forms.ModelForm erbt.
Der einfache Fall: Einen bestehenden Datensatz editieren.
Bis hier ist noch alles Standard.
Der komplexe Fall: Einen neuen Datensatz anlegen.
Das Anlegen soll in zwei Schritten geschehen:
- Schritt 1:
Erst wird eine ID eingegeben und dann [weiter] geklickt. Im Fehlerfall (not form.is_valid()) bleibt man auf der Seite und es erscheint eine Fehlermeldung. Sonst geht es weiter mit …
- Schritt 2:
Auf einer zweiten Formularseite ist die ID nicht mehr editierbar. Die weiteren, jetzt neu erscheinenden Felder sind teilweise vorbelegt.
Jetzt kommt die Stelle, mit der ich ein Problem habe:
Wenn ich das Formular beim Erzeugen mit Werten vorbelege, so wird es durch Django automatisch validiert. Falls die Validierung fehlschlägt – es könnte z.B. ein Pflichtfeld noch nicht vorausgefüllt sein – so wird dem User dies als Fehler mitgeteilt. Dieses Verhalten möchte ich vermeiden, da die Werte vom System und nicht vom User eingetragen werden. Das Formular soll erst dann validiert werden, wenn der User auf [Speichern] klickt.
Wie macht man so etwas?
Zusatzfrage: Verwendet man für jeden der beiden Schritte eine eigene Unterklasse von forms.ModelForm oder nimmt man immer die gleiche und ändert das Verhalten?
Schöne Grüße,
Olaf
[Django] Formular in zwei Schritten, wenn neuer Datensatz
Nachtrag:
ich habe als erste Lösung ein Flag im View gesetzt, welches im Template bestimmt, ob Validierungsfehler angezeigt werden oder nicht.
Nicht besonders schön, aber erst einmal funktionabel. Refactoring kommt dann später.
Grüße,
Olaf
ich habe als erste Lösung ein Flag im View gesetzt, welches im Template bestimmt, ob Validierungsfehler angezeigt werden oder nicht.
Nicht besonders schön, aber erst einmal funktionabel. Refactoring kommt dann später.
Grüße,
Olaf
Dies ist definitiv nicht das Verhalten von Django, wie belegst du die Werte vor? mit initial so wie du sollst? Zeig mal den Codefilchos hat geschrieben: Wenn ich das Formular beim Erzeugen mit Werten vorbelege, so wird es durch Django automatisch validiert. Falls die Validierung fehlschlägt – es könnte z.B. ein Pflichtfeld noch nicht vorausgefüllt sein – so wird dem User dies als Fehler mitgeteilt. Dieses Verhalten möchte ich vermeiden, da die Werte vom System und nicht vom User eingetragen werden. Das Formular soll erst dann validiert werden, wenn der User auf [Speichern] klickt.
Hallo apollo13,
ich musste den Viewcode kürzen, ich hoffe, er ist durch die Kommentare dennoch noch verständlich:
ich musste den Viewcode kürzen, ich hoffe, er ist durch die Kommentare dennoch noch verständlich:
Code: Alles auswählen
def edit(request, id):
# get optional instance
# if new: get step (1 or 2)
if id == 'new':
params = {}
step = int(request.POST.get('step', 1))
else:
params = {'instance': MyModel.objects.get(id=id)}
step = None
# assign the form class
if step == 1:
# form for the 1st step containing only a part of the fields
form_object = MyModelStep1Form
else:
# form for the 2nd step or editing containing all fields
form_object = MyModelForm
# get the matching form object
if request.method == 'POST':
form = form_object(request.POST, **params)
elif step == 1:
values = {
'key1': value1,
'key2': a_function_returning_value2(),
}
form = form_object(values, {})
else:
form = form_object(**params)
ignore_errors = False
if request.method == 'POST':
# validate and try to save
if form.is_valid():
if step == 1:
step += 1
# create another form with values from POST and a new calculated value3
values = {
'key1': request.POST.get('key1', None),
'key2': request.POST.get('key2', None),
'key3': a_function_returning_value3(),
}
form = MyModelForm(values)
ignore_errors = True
else:
form.save()
return my_own_redirect_function()
else:
ignore_errors = True
# display
return my_own_render_function(ignore_errors)
Hallo apollo13,
vielen Dank, wieder etwas über Django gelernt. Das Framework gefällt mir sehr gut, aber die Doku finde ich manchmal etwas unübersichtlich.
Grüße,
Olaf
Fürs Archiv:
Dokumentation dazu: http://docs.djangoproject.com/en/dev/re ... rm.initial
vielen Dank, wieder etwas über Django gelernt. Das Framework gefällt mir sehr gut, aber die Doku finde ich manchmal etwas unübersichtlich.
Grüße,
Olaf
Fürs Archiv:
Dokumentation dazu: http://docs.djangoproject.com/en/dev/re ... rm.initial
Folgefrage:
wie kann ich im Template nur den Wert eines Feldes anzeigen lassen?
Mein Versuch (Ausschnitt):
views.py:
template:
Leider erhalte ich als Ausgabe nicht den durch get_bar() errechneten Wert, sondern None.
Schöne Grüße,
Olaf
wie kann ich im Template nur den Wert eines Feldes anzeigen lassen?
Mein Versuch (Ausschnitt):
views.py:
Code: Alles auswählen
# […]
values = {'foo': get_bar(), }
form = form_object(initial=values)
# […]
Code: Alles auswählen
<p>{{form.foo.data}}</p>
Schöne Grüße,
Olaf
Die Frage ist natürlich berechtigt.apollo13 hat geschrieben:Gegenfrage, wofür brauchst du das?
Ich brauche diesen Wert, um ihn in einer von mir gewünschten Weise im Formular im Template anzeigen zu können.
Ich habe das zur Zeit gelöst, in dem ich ein Widget „ReadOnly“ geschrieben habe und dafür benutze. Das ist vermutlich auch der bessere Weg.
Die Frage bleibt daher mehr aus theoretischem Interesse bestehen.
Zusatzfrage: Kann ich im View nachträglich das verwendete Widget für ein Formularfeld ändern?
Grüße,
Olaf
wenn du die attrs auf readonly setzt heißt das nicht, dass der user das nicht verändern kann, nur zur info Wenn du nur den initial Wert anzeigen willst sollte form.field.initial gehenfilchos hat geschrieben: Ich habe das zur Zeit gelöst, in dem ich ein Widget „ReadOnly“ geschrieben habe und dafür benutze. Das ist vermutlich auch der bessere Weg.
form.fields['field_name'].widget = MyNewWidget, mit Vorsicht genießen…Zusatzfrage: Kann ich im View nachträglich das verwendete Widget für ein Formularfeld ändern?
Das ist klar. Der Wert wird bei meinem Widget als Hidden-Field im Formular übertragen. Natürlich wird der Wert validiert, denn der ist ja, wie jede Usereingabe – z.B. mit Firebug – schnell geändert.apollo13 hat geschrieben:wenn du die attrs auf readonly setzt heißt das nicht, dass der user das nicht verändern kann, nur zur info
Grüße,
Olaf