2012-04-05 5 views
5

Wir erstellen einen Assistenten mit der neuen Form Wizard-Funktionalität von Django 1.4.
Die Dokumente dazu sind sehr knapp und wir können keine erweiterten Beispiele finden. Wir verwenden einen benannten Schritt-Assistenten (der benötigt wird, um eine von uns verwendete ListView/DataGrid zu unterstützen) und ein Session-Backend. Der Assistent dient zum Bearbeiten von Rollen und verknüpften Rechten und ist so konzipiert, dass er sowohl Add- als auch Editierfunktionen bietet. Dazu fragen wir den Benutzer im ersten Schritt, ob er hinzufügen oder bearbeiten möchte.Benötigen Sie nähere Informationen zur Verwendung von Django 1.4 Form Wizards, insbesondere zum Vorfüllen und Speichern

Der nächste Schritt hängt von dieser Wahl ab; Wenn der Benutzer bearbeiten möchte, gibt es einen Suchbildschirm, gefolgt von , der die Ergebnisse anzeigt. Der Benutzer kann dann eines der Ergebnisse auswählen und geht zu einem Detailbildschirm, gefolgt von einer FilteredSelectMultiple Seite, die es ihm erlaubt, Rechte mit dieser Rolle zu verknüpfen.

Wenn der Benutzer eine neue Rolle hinzufügen möchte, werden die Such- und Ergebnisbildschirme übersprungen und der Benutzer wechselt direkt zum Detailbildschirm, gefolgt vom Link-Bildschirm.
es ist alles ziemlich gut funktioniert, ein condition_dict in urls.py verwenden, aber wir ein paar Dinge über die allgemeine Funktionalität fragen:

Wenn eine bestimmte vorbestehenden Rolle ausgewählt ist, wie können wir die füllen Details und der Link-Bildschirm mit den entsprechenden Daten?

Instanziieren wir ein Rollen-Objekt und übergeben es irgendwie an die zwei Formen, wenn ja, wo instanziieren wir es und müssen wir das für jedes Formular separat machen (was etwas übertrieben erscheint)?

Beim Speichern ist es üblich, eine weitere Instanz eines Rollenobjekts zu erstellen, die Formulardaten hinzuzufügen und zu speichern, oder können wir das in den Formularen verwendete Objekt irgendwie wiederverwenden?

Wir haben versucht, eine Überlastung get_form_instance Instanzen von Rollen zurückzukehren, und wir haben bei instance_dict in der Dokumentation sah, aber es fühlt sich an wie der falsche Ansatz und gibt es keine Beispiele online gefunden werden, und wir sind nicht einmal sicher, dass diese verwendet werden, um Daten vorzufüllen oder auch wenn wir auf dem richtigen Weg sind.

Logischerweise würde ich sagen, in dem Schritt, der eine vorhandene Rolle auswählt, muss ich die Wizard-Variablen mit einer Instanz des ausgewählten Objekts füllen, und diese werden in den Formularen angezeigt. Am Ende des Assistenten kehren wir den Prozess um und holen alle Daten aus den Wizard-Variablen und fügen sie zu einem neu instanziierten Rollenobjekt hinzu und speichern es. Idealerweise wird diese Instanz selbst bestimmen, ob sie ein INSERT oder ein UPDATE ausführen muss, abhängig davon, ob der Promary-Schlüssel gefüllt ist oder nicht.

Wenn jemand ein Beispiel oder einen Anstupser in die richtige Richtung geben kann, würde es sehr geschätzt werden.

Der Code der wizardview Klasse in views.py unter:

class RolesWizard(NamedUrlSessionWizardView): 

def get_template_names(self): 
    # get template for each step... 
    if self.steps.current == 'choice': 
     return 'clubassistant/wizard_neworeditrole.html' 
    if self.steps.current == 'search': 
     return 'clubassistant/wizard_searchrole.html' 
    if self.steps.current == 'results': 
     return 'clubassistant/wizard_pickrole.html' 
    if self.steps.current == 'details': 
     return 'clubassistant/wizard_detailsrole.html' 
    elif self.steps.current == 'rights': 
     return 'clubassistant/wizard_roles.html' 

def get_context_data(self, form, **kwargs): 
    # get context data to be passed to the respective templates 
    context = super(RolesWizard, self).get_context_data(form=form, **kwargs) 

    # add the listview in the results screen 
    if self.steps.current == 'results': 
     # get search text from previous step 
     cleaned_data = self.get_cleaned_data_for_step('search') 
     table = RolesTable(Roles.objects.filter(
      role_name__contains=cleaned_data['searchrole']) 
     ) 
     RequestConfig(self.request, paginate={ 
      "per_page": 4, 
      }).configure(table) 
     # add the listview with results 
     context.update({'table': table}) 

    # add a role instance based on the chosen primary key 
    if self.steps.current == 'rights': 
     cleaned_data = self.get_cleaned_data_for_step('results') 
     role_id = cleaned_data['role_uuid'] 
     role = get_object_or_404(Roles, pk=role_id) 
     context.update({'role': role}) 

    return context 

def done(self, form_list, **kwargs): 
    # this code is executed when the wizard needs to be completed 

    # combine all forms into a single dictionary 
    wizard = self.get_all_cleaned_data() 

    if wizard.get("neworeditrole")=="add": 
     role = Roles() 
    else: 
     role = get_object_or_404(Roles, pk=wizard.get("role_uuid")) 

    # many-to-many rights/roles 
    role.role_rights_new_style.clear() 
    for each_right in wizard.get('role_rights_new_style'): 
     RightsRoles.objects.create(role=role, right=each_right,) 

    # other properties 
    for field, value in self.get_cleaned_data_for_step('details'): 
     setattr(role, field, value) 

    role.save() 

    # return to first page of wizard... 
    return HttpResponseRedirect('/login/maintenance/roles/wizard/choice/') 

Antwort

1

Mal sehen, ob ich helfen kann. Ich habe einen Formularassistenten gemacht, der je nach den Antworten Schritte hinzufügt.Bei jedem Schritt speichere ich alle Formen in einer Session-Variablen, etwa so:

def process_step(self, request, form, step): 
    request.session['form_list'] = self.form_list 
    request.session['initial'] = self.initial 

Dann jedes Mal, wenn gemacht wird, zu sehen, instanziieren ich einen neuen Formular-Assistenten mit all vorherigen Daten:

def dynamic_wizard(request): 
    if not request.session.get('form_list'): 
     form = Wizard([Form1]) 
    else: 
     form = Wizard(request.session.get('form_list'), initial = request.session['initial']) 
    return form(context=RequestContext(request), request=request) 
+0

Dies war Django 1.3. – daigorocub

2

Für zukünftige Googler:

Ich hatte etwas Erfolg mit get_form(), weil es aufgerufen wird, bevor ein Formular gerendert wird. Beginnen Sie mit ein paar ModelForms:

class Wizard1(models.ModelForm): 
    class Meta: 
     model = MyModel 
     fields = ('field0', 'model0') 
class Wizard2(models.ModelForm): 
    class Meta: 
     model = MyModel 
     excludes = ('field0', 'model0') 

Dann in Ihrem SessionWizardView:

class MyWizard(SessionWizardView): 
    def get_form(self, step=None, data=None, files=None): 
     form = super(ExtensionCreationWizard, self).get_form(step, data, files) 

     if step is not None and data is not None: 
      # get_form is called for validation by get_cleaned_data_for_step() 
      return form 

     if step == "0": 
      # you can set initial values or tweak fields here 

     elif step == "1": 
      data = self.get_cleaned_data_for_step('0') 
      if data is not None: 
       form.fields['field1'].initial = data.get('field0') 
       form.fields['field2'].widget.attrs['readonly'] = True 
       form.fields['field3'].widget.attrs['disabled'] = True 
       form.fields['model1'].queryset = Model1.objects.filter(name="foo") 

     return form 

Die Aktion ist alles in Schritt 1. Sie anfordern validierten Daten aus Schritt 0 (was einen weiteren Anruf auslöst get_form () für Schritt 0, also seien Sie vorsichtig) und dann können Sie auf alle Werte zugreifen, die in Schritt 0 eingestellt wurden.

Ich warf ein paar Beispiele für Einstellungen, die Sie auf den Feldern ändern können. Sie können ein Abfrageset aktualisieren, um die Werte in einem ChoiceField einzuschränken, oder einen Wert erneut anzeigen, aber schreibgeschützt machen. Eine Einschränkung, die mir aufgefallen ist, ... funktioniert bei ChoiceField nicht. Sie können es deaktivieren, aber der Wert wird nicht weitergegeben, wenn Sie das Formular absenden.

+0

So geht's! – JeffC

+0

hmm, "get_form" -Methode ist meiner Meinung nach hier ein bisschen unglücklich, da alle formellen Dinge in der Formularklasse selbst aufbewahrt werden sollten. Ein besserer Weg besteht darin, get_form_kwargs zum Setzen von "Flags" zu verwenden und diese dann zum Anpassen von Feldern innerhalb der Form-Init-Methode zu verwenden. – mariodev

Verwandte Themen