3 Stimmen

Wie man ein "Workflow"-Formular erstellt

Für mein Projekt benötige ich viele "Workflow"-Formulare. Ich erkläre mich selbst:

Der Benutzer wählt im ersten Feld einen Wert aus, validiert das Formular und je nach dem Wert des ersten Feldes erscheinen neue Felder. Dann können abhängig von den anderen Feldern neue Felder erscheinen...

Wie kann ich das auf generische Weise umsetzen?

3voto

lprsd Punkte 80189

Ich denke, die Lösung, die Sie suchen, lautet django form wizard

Im Grunde definieren Sie separate Formulare für verschiedene Seiten und passen die nächsten auf der Grundlage der Eingaben in den vorherigen Bildschirmen an.

Sehen Sie sich insbesondere die Prozessschritt erweiterte Option im Formularassistenten.

FormWizard.process_step()
"""
Hook for modifying the wizard's internal state, given a fully validated Form object. The Form is guaranteed to have clean, valid data.
This method should not modify any of that data. Rather, it might want to set self.extra_context or dynamically alter self.form_list, based on previously submitted forms.
Note that this method is called every time a page is rendered for all submitted steps.
The function signature:
"""

def process_step(self, request, form, step):
    # ...

Wenn Sie die Dropdown-Werte nur auf der Grundlage anderer Dropdowns innerhalb desselben Formulars ändern möchten, sollten Sie sich die implementierte dajaxproject

1voto

Ich denke, es kommt auf das Ausmaß des Problems an.

Sie könnten ein generisches JavaScript schreiben, das die Formularfelder ein- und ausblendet (im Formular selbst wenden Sie dann diese CSS-Klassen an). Dies würde bei einer relativ kleinen Anzahl von ein- und ausblendbaren Feldern gut funktionieren.

Wenn Sie weiter gehen wollen, müssen Sie über die Entwicklung dynamischer Formulare in Django nachdenken. Ich würde vorschlagen, dass Sie die ['field'] in der Klasse nicht ändern, wie Ghislain vorgeschlagen hat. Es gibt einen guten Beitrag hier über dynamische Formen und zeigt Ihnen ein paar Ansätze.

Ich könnte mir vorstellen, dass eine gute Lösung darin bestehen könnte, die dynamischen Formulare im obigen Beitrag mit dem django FormWizard . Der FormWizard führt Sie durch verschiedene Formulare und ermöglicht Ihnen am Ende die Speicherung der Gesamtdaten.

Es gab allerdings ein paar Probleme, da man nicht einfach einen Schritt zurückgehen kann, ohne die Daten des aktuellen Schritts zu verlieren. Auch die Anzeige aller Formulare erfordert eine gewisse Anpassung des FormWizard. Ein Teil der API ist nicht dokumentiert oder wird als öffentlich angesehen (also Vorsicht vor Änderungen in zukünftigen Versionen von Django), aber wenn Sie sich die die Quelle können Sie Teile des Formularassistenten relativ einfach erweitern und überschreiben, um das zu tun, was Sie brauchen.

Ein einfacherer Ansatz für den FormWizard wäre es, 5 statische Formulare zu haben und dann die Formularauswahl im Assistenten anzupassen und zu ändern, welche Formulare als nächstes angezeigt werden und nur die relevanten Formulare anzuzeigen. Auch dies würde gut funktionieren, aber es hängt davon ab, wie sehr sich die Formulare aufgrund früherer Auswahlen ändern.

Ich hoffe, das hilft, stellen Sie Fragen, wenn Sie welche haben!

0voto

Peter Rowell Punkte 17345

Es klingt, als ob Sie eine AJAX-artige Lösung wünschen. Prüfen Sie die Taconit-Plugin für jQuery. Ich benutze dies für das Auffüllen von Pulldowns, etc. auf Formen. Funktioniert sehr gut.

Was die "Generizität" angeht ... Sie könnten Standardmethoden in Ihren Containerklassen haben, die Listen von Kindern zurückgeben, und dann ein Vorlagenfragment haben, das weiß, wie man das auf eine "Standard"-Art formatiert.

0voto

Ghislain Leveque Punkte 908

Ok, ich habe eine Lösung gefunden, die nicht ajax überhaupt verwenden und scheint nett genug, um mich:

Erstellen Sie so viele Formulare wie nötig und machen Sie sie zu Unterklassen. Fügen Sie in das erste Formular ein verstecktes Integer-Feld ein:

class Form1(forms.Form):
    _nextstep = forms.IntegerField(initial = 0, widget = forms.HiddenInput())
    foo11 = forms.IntegerField(label = u'First field of the first form')
    foo12 = forms.IntegerField(label = u'Second field of the first form')

class Form2(Form1):
    foo21 = forms.CharField(label = u'First field of the second form')

class Form3(Form2):
    foo31 = forms.ChoiceField([],
        label=u'A choice field which choices will be completed\
            depending on the previous forms')
    foo32 = forms.IntegerField(label = u'A last one')

    # You can alter your fields depending on the data.
    # Example follows for the foo31 choice field
    def __init__(self, *args, **kwargs):
        if self.data and self.data.has_key('foo12'):
            self.fields['foo31'].choices = ['make','a','nice','list',
                'and you can','use your models']

Ok, das war für die Formulare, hier ist die Ansicht:

def myview(request):
    errors = []
    # define the forms used :
    steps = [Form1,Form2,Form3]
    if request.method != 'POST':
        # The first call will use the first form :
        form = steps[0]()
    else:
        step = 0
        if request.POST.has_key('_nextstep'):
            step = int(request.POST['_nextstep'])
        # Fetch the form class corresponding to this step
        # and instantiate the form
        klass = steps[step]
        form = klass(request.POST)
        if form.is_valid():
            # If the form is valid, increment the step
            # and use the new class to create the form
            # that will be displayed
            data = form.cleaned_data
            data['_nextstep'] = min(step + 1, len(steps) - 1)
            klass = steps[data['_nextstep']]
            form = klass(data)
        else:
            errors.append(form.errors)
    return render_to_response(
        'template.html',
        {'form':form,'errors':errors},
        context_instance = RequestContext(request))

Das einzige Problem, das ich gesehen habe, ist, dass bei Verwendung von {{form}} in der Vorlage form.errors aufgerufen wird und somit das neue Formular (z. B. Form2) automatisch mit den Daten des vorherigen Formulars (Form1) validiert wird. Ich iteriere also über die Elemente im Formular und verwende nur {{item.id}}, {{item.label}} und {{item}}. Da ich die Fehler des vorherigen Formulars bereits in der Ansicht abgerufen und an die Vorlage übergeben habe, füge ich ein Div hinzu, um sie oben auf der Seite anzuzeigen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X