Plone で複数の z3c フォームを次々にチェーンできるようにしたいと考えています。たとえば、フォーム #1 が処理を終了してエラー チェックを完了すると、結果が (できれば GET 変数を介して) フォーム #2 に渡され、フォーム #2 が同じことをフォーム #3 などに渡します。すべてのフォームに同じ URL を使用できます。
私の現在の実装では、適切なフォームをディスパッチするブラウザ ビューを用意しています。つまり、DispatcherView は self.request 変数をチェックし、form#1、form#2、form#3 のどれを呼び出すかを決定します。
私はこのコードを持っていますが、z3cフォームはBrowserViewへの複数の呼び出しとして抽象化されているようです.z3c.formへの複数の呼び出しをトリガーしようとすると、後者の処理が妨げられます. たとえば、ユーザーが「送信」ボタンを1回押すと、フォーム#1のエラーチェックが行われ、以下の例の解決策を試すと、フォーム#2が返され、すべての必須フィールドが正しくないことを示します。これは、フォーム#2が値を受け取ったことを意味しますフォーム#1。DispatcherView(BrowserView) call () メソッド、 form#1 のcall () メソッド、後者の update() と render() など、さまざまな場所から form#2 をトリガーしようとしましたが、これらのオーバーライドはすべて同じ問題。
このことが機能するように連続した呼び出しをピギーバックする適切な場所はどこですか、または別のページを作成し、 self.request.RESPONSE.redicrect を使用して明示的に相互にリダイレクトする必要がありますか?
from Products.Five import BrowserView
from zope import interface, schema
from z3c.form import form, field, group, button
from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm
countries = SimpleVocabulary([SimpleTerm(value="not_selected", title=_("Chose your region")),
SimpleTerm(value="canada", title=_("Canada")),
SimpleTerm(value="us", title=_("United States")),
SimpleTerm(value="belgium", title=_("Belgium"))])
products = SimpleVocabulary([SimpleTerm(value="product1", title=_("Product1")),
SimpleTerm(value="product2", title=_("Product2")),
SimpleTerm(value="product3", title=_("Product2"))
])
class DispatcherView(BrowserView):
def __call__(self):
if 'form.widgets.region' in self.request.keys():
step2 = Step2(self.context, self.request)
return step2.__call__()
else:
step1 = Step1(self.context, self.request)
return step1.__call__()
def update(self):
pass
class IStep1(interface.Interface):
region = schema.Choice(title=_("Select your region"),
vocabulary=countries, required=True,
default="not_selected")
class IStep2(interface.Interface):
product = schema.Choice(title=_("Pick a product"),
vocabulary=products, required=True)
class Step1(form.Form):
fields = field.Fields(IStep1)
def __init__(self,context, request):
self.ignoreContext = True
super(self.__class__, self).__init__(context, request)
def update(self):
super(self.__class__, self).update()
@button.buttonAndHandler(u'Next >>')
def handleNext(self, action):
data, errors = self.extractData()
if errors:
print "Error occured"
class Step2(form.Form):
fields = field.Fields(IStep2)
def __init__(self,context, request):
self.ignoreContext = True
super(self.__class__, self).__init__(context, request)
def update(self):
super(self.__class__, self).update()
@button.buttonAndHandler(_('<< Previous'))
def handleBack(self, action):
data, errors = self.extractData()
if errors:
print "Error occured"
#handle input errors here
@button.buttonAndHandler(_('Next >>'))
def handleNext(self, action):
data, errors = self.extractData()
if errors:
print "Error occured"
編集: Cris Ewing がこれに対する回答を提供しました。collective.z3cformwizard を使用して書き直した後のサンプル コードは次のようになります。
from zope import schema, interface
from zope.interface import implements
from z3c.form import field, form
from collective.z3cform.wizard import wizard
from plone.z3cform.fieldsets import group
from plone.z3cform.layout import FormWrapper
from Products.statusmessages.interfaces import IStatusMessage
from Products.statusmessages.adapter import _decodeCookieValue
from zope.schema.vocabulary import SimpleVocabulary, SimpleTerm
from z3c.form.browser.checkbox import CheckBoxFieldWidget
from Products.Five import BrowserView
countries = SimpleVocabulary([SimpleTerm(value="not_selected", title=_("Chose your region")),
SimpleTerm(value="belgium", title=_("Belgium")),
SimpleTerm(value="canada", title=_("Canada")),
SimpleTerm(value="us", title=_("United States")),
])
products = SimpleVocabulary([SimpleTerm(value="product1", title=_("Product1")),
SimpleTerm(value="product2", title=_("Product2")),
SimpleTerm(value="product3", title=_("Product3")),
SimpleTerm(value="product4", title=_("Product4")),
SimpleTerm(value="product5", title=_("Product5"))
])
class Step1(wizard.Step):
prefix = 'one'
fields = field.Fields(schema.Choice(__name__="region",
title=_("Select your region"), vocabulary=countries,
required=True, default="not_selected")
)
class Step2(wizard.Step):
prefix = 'two'
fields = field.Fields(schema.List(__name__="product",
value_type=schema.Choice(
title=_("Select your product"),
vocabulary=products),
required=True
)
)
for fv in fields.values():
fv.widgetFactory = CheckBoxFieldWidget
class WizardForm(wizard.Wizard):
label= _("Find Product")
steps = Step1, Step2
def finish(self):
##check answer here
import pdb; pdb.set_trace()
class DispatcherView(FormWrapper):
form = WizardForm
def __init__(self, context, request):
FormWrapper.__init__(self, context, request)
def absolute_url(self):
return '%s/%s' % (self.context.absolute_url(), self.__name__)
また、configure.zcml の browser:view slug も忘れないでください。
<browser:page
name="view"
for="Products.myproduct.DispatcherView"
class=".file.DispatcherView"
permission="zope2.View"
/>