2014-01-21 8 views
8

Ich habe kürzlich Django-Formulare von Unterklasse FormView gelernt, wo die gewünschte Form dem FormView.form_class Attribut zugeordnet ist. Wenn das Formular validiert wird, wird die form_valid()-Methode aufgerufen (für dieses eine Formular). Zum Beispiel:Django: Mehrere Formulare möglich, wenn FormView verwendet wird?

from accounts.forms import SignUpForm, UpdateAccountForm, UpdateBillingForm 

class SignUpView(FormView): 
    form_class = SignUpForm 

    def form_valid(self, form): 
    # code when form validates... 

Allerdings habe ich jetzt eine Situation, wo ich brauche drei einzigartige Formen auf einer Seite (mit nur einem Formular für den Benutzer sichtbar zu einem Zeitpunkt). Also, ich möchte sie alle in der gleichen Ansicht behandeln.

Sind mit FormView mehrere Seiten möglich? Ich bin mir nicht sicher, wie ich damit umgehen soll, sowohl was die Übergabe mehrerer Formulare an das View anbelangt (z. B. das andere UpdateAccountForm- und UpdateBillingForm-Formular), als auch die Unterscheidung zwischen dem gesendeten und validierten Formular. Was wäre der beste Weg?

+0

Sieht aus wie es mit Formview nicht möglich ist (?). Pro diese [Antworten] (http://stackoverflow.com/questions/1395807/proper-way-to-handle-multiple-forms-on-one-page-in-django), sollte man eine generische Ansicht verwenden und hinzufügen Präfixe (?) – pete

+1

Ich habe gerade ein Tool geschrieben, um genau dieses Ding zu tun, nur teilweise dokumentiert ab sofort, aber die Klasse MultFormView ist nur ein paar Zeilen Code genau das, was Sie versuchen, https://github.com zu tun/dm03514/django-CBV-Toolkit – dm03514

Antwort

0

Sie können eine einfache Python-Klasse schreiben, die die Form API nachahmt (zumindest die nützlichen Teile) und Ihre drei Formulare umschließt. Um festzustellen, welches Formular gesendet wurde, muss nur eine verborgene Eingabe mit der Kennung des Formulars in jedem Formular hinzugefügt werden (Hinweis: Verwenden Sie für Ihre Formulare Präfixe und verwenden Sie dasselbe Präfix als Bezeichner).

Die andere Lösung ist stattdessen eine einfache Funktion-basierte Ansicht zu verwenden, aber selbst dort würde ich immer noch das gleiche "Formular Wrapper" -Muster verwenden, soweit es mich betrifft.

10

Nun, was es wert ist hier ist, was letztlich für mich funktionierte, mit einem generischen View.

1) Ich habe jedes einzelne Formular auf der Seite mit einem versteckten Eingabefeld ('Aktion') versehen. Zum Beispiel ist dies die Form für Benutzer-Informationen zu aktualisieren, die in Userform zieht:

<form action='/account/' method='post'>{% csrf_token %} 
    <input type='hidden' name='action' value='edit_user'> 
    {{ user_form.as_p }} 
    <input type='submit' value='Update'> 
</form> 

2) Meiner Ansicht Logik kann ich die Formulare durch Anlegen eines Präfix unterscheiden (pro andere SO Beiträge und Django docs) . Dann binde ich abhängig von der eingehenden 'Aktion' nur das anwendbare Formular an die POST-Anfrage (so werden Validierungen nicht auf alle angewendet). In meinem Fall, ich in forms.py, Userform und BillingForm definiert zwei Formen hatte:

from django.views.generic.edit import View 
from django.shortcuts import render 
from django.http import HttpResponse 

from accounts.forms import UserForm, BillingForm 

class AccountView(View): 

    def get(self, request): 
     # code for GET request... 

    def post(self, request): 
     #instantiate all unique forms (using prefix) as unbound 
     user_form = UserForm(prefix='user_form') 
     billing_form = BillingForm(prefix='billing_form') 

     # determine which form is submitting (based on hidden input called 'action') 
     action = self.request.POST['action'] 

     # bind to POST and process the correct form 
     if (action == 'edit_user'): 
      user_form = UserForm(request.POST, prefix='user_form') 
      if user_form.is_valid(): 
       # user form validated, code away.. 

     elif (action == 'edit_billing'): 
      billing_form = BillingForm(request.POST, prefix='billing_form') 
      if billing_form.is_valid(): 
       # billing form validated, code away.. 

     # prep context 
     context = { 
      'user_form': user_form, 
      'billing_form': billing_form, 
     } 
     return render(request, 'accounts/account.html', context) 

scheint gut zu funktionieren, hoffentlich ist dies der richtige Ansatz

Verwandte Themen