2014-11-21 54 views
1

Django文檔沒有很好地記錄在這個主題上。事實上,他們在文檔具有唯一的參考是這一段:如何在Form Wizard中使用ModelFormSet

如何使用的ModelForm和ModelFormSet

WizardView.instance_dict工作。 WizardView支持ModelForms和ModelFormSets。除了initial_dict之外,as_view()>方法還包含一個instance_dict參數,該參數應該包含基於ModelForm的步驟的模型實例和基於ModelFormSet的步驟的查詢集。

我還沒有找到任何有關如何使用它的好的和清晰的例子。有人可以幫我弄這個嗎?

具體做法是:

  • 什麼在forms.py嗎?
  • 如果我只需要FormForm的某些步驟而不是所有的步驟,該怎麼辦?
  • 我需要在views.py和模板中做什麼?

爲了把一個用例和小項目我工作的一個作爲一個例子,我分享我的代碼:

  • 使用案例:
    • 用戶希望在一個多形式註冊,他在第一步介紹他的名字和姓氏。
  • 在第二步中,他介紹了他的護照號碼和酒店註冊信息,他還想註冊他的兒子和妻子,這些人將與他一起去這家酒店(這裏我想用HotelRegistration模型中的modelformset )。
  • 在第三步他輸入他的航班信息。然後,如果表單有效並保存在數據庫中,則會收到一條確認消息。

這裏是我的代碼:

models.py

class Event(models.Model): 

    name = models.CharField(max_length=100) 
    date_from = models.DateField(auto_now=False) 
    date_to = models.DateField(auto_now=False) 
    description = models.TextField() 

    def __unicode__(self): 
     return self.name 


class Hotel(models.Model): 
    name = models.CharField(max_length=50) 
    address = models.CharField(max_length=100) 

    def __unicode__(self): 
     return self.name 


class HotelRegistration(models.Model): 
    pax_first_name = models.CharField(max_length=50) 
    pax_last_name = models.CharField(max_length=50) 
    hotel = models.ForeignKey(Hotel) 

    def __unicode__(self): 
     return self.pax_first_name 


class Registration(models.Model): 

    first_name = models.CharField(max_length=50) 
    last_name = models.CharField(max_length=50) 
    passport = models.CharField(max_length=15) 
    city_origin = models.CharField(max_length=50) 
    flight_date_from = models.DateField(auto_now=False) 
    flight_date_to = models.DateField(auto_now=False) 
    require_transfer = models.BooleanField(default=None) 
    event = models.ForeignKey(Event) 
    hotel_registration = models.ForeignKey(HotelRegistration, blank=True, null=True) 

    def __unicode__(self): 
     return self.first_name 

forms.py

from django import forms 

from .models import Registration 

class FormStep1(forms.ModelForm): 
    class Meta: 
     model = Registration 
     fields = ['first_name', 'last_name'] 
     widgets = { 
      'first_name': forms.TextInput(attrs={'placeholder': 'Nombre de la persona que esta reservando', 'label_tag': 'Nombre'}), 
     'last_name': forms.TextInput(attrs={'placeholder': 'Apellido'}) 
    } 

class FormStep2(forms.ModelForm): 
    class Meta: 
     model = Registration 
     fields = ['passport', 'hotel_registration'] 
     exclude = ('first_name', 'last_name', 'event' , 'city_origin', 'flight_date_from', 'flight_date_to', 'require_transfer') 
     widgets = { 
      'passport': forms.NumberInput(attrs={'placeholder':'Escriba su pasaporte'}) 
     } 

class FormStep3(forms.ModelForm): 
    class Meta: 
     model = Registration 
     fields = ['city_origin', 'flight_date_from', 'flight_date_to', 'require_transfer', 'event'] 
     exclude = ('first_name', 'last_name', 'hotel_registration') 
     widgets = { 
      'city_origin': forms.TextInput(attrs={'placeholder':'Ciudad desde donde esta viajando'}), 
      'flight_date_from': forms.DateInput(format=('%d-%m-%Y'), attrs={'class':'myDateClass', 'placeholder':'Select a date'}), 
      'flight_date_to': forms.DateInput(format=('%d-%m-%Y'), attrs={'class':'myDateClass', 'placeholder':'Select a date'}), 
      'require_transfer': forms.Select(), 
      'event': forms.Select() 
    } 

views.py

from django.shortcuts import render 
from django.contrib.formtools.wizard.views import SessionWizardView 
from django.http import HttpResponseRedirect 
from django.views.generic import TemplateView 
from django.forms.models import inlineformset_factory 

from .models import Registration, HotelRegistration 
from .forms import FormStep1, FormStep2, FormStep3 


FORMS = [ 
    ("step1", FormStep1), 
     ("step2", FormStep2), 
     ("step3", FormStep3) 
] 

TEMPLATES = { 
    "step1" : "wizard/step1.html", 
    "step2" : "wizard/step2.html", 
    "step3" : "wizard/step3.html" 
} 


class TestFormWizard(SessionWizardView): 

    instance = None 

def get_form_instance(self, step): 
    if self.instance is None: 
     self.instance = Registration() 
    return self.instance 


def get_form(self, step=None, data=None, files=None): 
    form = super(TestFormWizard, self).get_form(step, data, files) 
    HotelRegistFormSet = inlineformset_factory(HotelRegistration, Registration, can_delete=True, extra=1) 

    # determine the step if not given 
    if step is None: 
     step = self.steps.current 

    if step == '2': 
     hotel_registration_formset = HotelRegistFormSet(self.steps.current, self.steps.files, prefix="step2") 
    return form 


def get_template_names(self): 
    return [TEMPLATES[self.steps.current]] 

def done(self, form_list, **kwargs): 
    self.instance.save() 
    return HttpResponseRedirect('/register/confirmation') 


class ConfirmationView(TemplateView): 
    template_name = 'wizard/confirmation.html' 

模板

{% extends "base.html" %} 
    {% load i18n %} 


    {% block content %} 
    <p>Step {{ wizard.steps.step1 }} of {{ wizard.steps.count }}</p> 
    <form action="" method="post">{% csrf_token %} 
    <table> 
     {{ wizard.management_form }} 
      {% if wizard.form.forms %} 
     {{ wizard.form.management_form }} 
     {% for form in wizard.form.forms %} 
      {{ form }} 
     {% endfor %} 
    {% else %} 
     {{ wizard.form }} 
    {% endif %} 
    </table> 
    {% if wizard.steps.prev %} 
    <button name="wizard_goto_step" type="submit" value="{{ wizard.steps.first }}">{% trans "first step" %}</button> 
    <button name="wizard_goto_step" type="submit" value="{{ wizard.steps.prev }}">{% trans "prev step" %}</button> 
    {% endif %} 
    <input type="submit" value="{% trans "submit" %}"/> 
    </form> 
    {% endblock %} 
+0

你有沒有得到這個解決?我即將放棄使用帶嚮導視圖的模型框架。 – 2015-04-18 23:19:45

+0

你有沒有得到這個解決?你呢,Nostalgio? – 2016-08-24 15:28:27

回答

3

在forms.py中做些什麼?

重寫SessionWizardView的get_form_instance方法。這是FormWizard使用,以確定是否一個模型實例用於W/A模型形式的方法

WizardView.get_form_instance(步驟) 如果一個的ModelForm被用作形成用於步驟該方法將被稱爲僅步。 返回一個Model對象,該對象在實例化用於步驟的ModelForm時將作爲實例參數傳遞。如果在初始化表單嚮導時未提供實例對象,則將返回None。

這可以在SessionWizardView實現中按步驟有條件地完成。我不明白你想做的事情足以給你一個確切的例子,所以這裏是一個更通用的例子。

def get_form_instance(self, step): 
    if step == u'3': 
     past_data = self.get_cleaned_data_for_step(u'2') 
     hotel_name = past_data['hotel_field'] 
     hotel = Hotel.objects.get(name=hotel_name) 
     return hotel #do NOT set self.instance, just return the model instance you want 
    return self.instance_dict.get(step, None) # the default implementation 

如果我需要什麼ModelFormSet只在形式的某些步驟,而不是所有的人?

見上;使用'if step ==(表單/步驟名稱)'表達式來確定每個步驟會發生什麼。

我需要在views.py和模板中做什麼?

使用ModelForm並向其傳遞模型對象實例將設置初始表單值。你需要更多嗎?

希望這會向您顯示FormWizard中預期的結構。比我使用的Django的任何其他部分都多,FormWizard需要一個非常特定的結構,並且是一個單一的類。