基于z3c.form的Zope3向导
项目描述
此包提供基于z3c.form的Zope3表单向导概念。
向导
本包的目标是提供一个表单向导。此实现不使用会话。它只提供向导逻辑,向导将更改或添加的数据不是此实现的一部分。如果您想实现一些额外的向导逻辑,您可能需要使用会话并在不同的向导步骤中收集值,并在向导的 doComplete 或 doFinish 或步骤的 doComplete 方法中创建和添加对象。
所有步骤都可通过自己的URL访问。这使我们能够根据需要缓存每个步骤。每个步骤URL仅在我们允许访问该步骤时才可用。一个步骤是否可访问取决于每个步骤的条件。
因为步骤是适配器,我们可以为已存在的向导注册步骤,或者也可以通过注册一个总是返回False的UnavailableStep步骤来覆盖现有的步骤。
如果向导已完成,我们将被重定向到确认页面。如果我们再次访问已完成的向导,我们还会被重定向到确认页面。
现在让我们展示它是如何工作的,并设置我们的测试。
表单支持
我们需要加载formui配置,这将确保所有宏都能正确注册。
>>> from zope.configuration import xmlconfig >>> import z3c.form >>> import z3c.formui >>> import z3c.macro >>> import z3c.template >>> import zope.browserresource >>> import zope.component >>> import zope.i18n >>> import zope.security >>> import zope.viewlet >>> xmlconfig.XMLConfig('meta.zcml', z3c.form)() >>> xmlconfig.XMLConfig('meta.zcml', z3c.macro)() >>> xmlconfig.XMLConfig('meta.zcml', z3c.template)() >>> xmlconfig.XMLConfig('meta.zcml', zope.browserresource)() >>> xmlconfig.XMLConfig('meta.zcml', zope.component)() >>> xmlconfig.XMLConfig('meta.zcml', zope.i18n)() >>> xmlconfig.XMLConfig('meta.zcml', zope.security)() >>> xmlconfig.XMLConfig('meta.zcml', zope.viewlet)() >>> xmlconfig.XMLConfig('configure.zcml', z3c.form)() >>> xmlconfig.XMLConfig('configure.zcml', z3c.formui)()
然后加载z3c.wizard宏配置。
>>> import z3c.wizard >>> xmlconfig.XMLConfig('configure.zcml', z3c.wizard)()
示例数据设置
让我们定义一个示例内容类。
>>> import zope.interface >>> import zope.schema >>> from zope.location.interfaces import ILocation >>> from zope.schema.fieldproperty import FieldProperty >>> class IPerson(ILocation): ... """Person interface.""" ... ... firstName = zope.schema.TextLine(title=u'First Name') ... lastName = zope.schema.TextLine(title=u'Last Name') ... street = zope.schema.TextLine(title=u'Street') ... city = zope.schema.TextLine(title=u'City')>>> @zope.interface.implementer(IPerson) ... class Person(object): ... """Person content.""" ... ... ... __name__ = __parent__ = None ... ... firstName = FieldProperty(IPerson['firstName']) ... lastName = FieldProperty(IPerson['lastName']) ... street = FieldProperty(IPerson['street']) ... city = FieldProperty(IPerson['city'])
为我们的向导设置一个人物。
>>> person = Person() >>> root['person'] = person >>> person.__parent__ = root >>> person.__name__ = u'person'
步骤
让我们定义一些步骤。首先使用一个知道如何存储人物名称的步骤。
>>> from z3c.form import form >>> from z3c.form import field >>> from z3c.wizard import step>>> class PersonStep(step.EditStep): ... label = u'Person' ... fields = field.Fields(IPerson).select('firstName', 'lastName')
然后为收集一些地址数据定义另一个步骤。
>>> class AddressStep(step.EditStep): ... label = u'Address' ... fields = field.Fields(IPerson).select('street', 'city')
向导
现在我们可以定义我们的Wizard,包括我们的步骤。步骤是命名适配器。让我们使用全局方法addStep来进行步骤设置。
>>> from z3c.wizard import wizard >>> class IPersonWizard(z3c.wizard.interfaces.IWizard): ... """Person wizard marker.""">>> @zope.interface.implementer(IPersonWizard) ... class PersonWizard(wizard.Wizard): ... ... label = u'Person Wizard' ... ... def setUpSteps(self): ... return [ ... step.addStep(self, 'person', weight=1), ... step.addStep(self, 'address', weight=2), ... ]
接下来,我们需要将我们的步骤注册为命名的IStep适配器。这可以通过z3c:wizardStep指令完成。现在让我们使用provideAdapter方法定义我们的适配器。
>>> import zope.interface >>> from zope.publisher.interfaces.browser import IDefaultBrowserLayer >>> from zope.publisher.interfaces.browser import IBrowserRequest >>> import z3c.wizard.interfaces >>> zope.component.provideAdapter( ... PersonStep, (None, IBrowserRequest, None), ... z3c.wizard.interfaces.IStep, name='person')>>> zope.component.provideAdapter( ... AddressStep, (None, IBrowserRequest, None), ... z3c.wizard.interfaces.IStep, name='address')
我们需要支持我们的请求的div表单层。这是因为我们在步骤中使用的表单部分。因为我们的步骤是表单。
>>> from z3c.formui.interfaces import IDivFormLayer >>> from zope.interface import alsoProvides >>> import zope.publisher.browser >>> import z3c.form.interfaces >>> @zope.interface.implementer(z3c.form.interfaces.IFormLayer) ... class TestRequest(zope.publisher.browser.TestRequest): ... pass >>> request = TestRequest() >>> alsoProvides(request, IDivFormLayer)
现在我们可以使用我们的向导。我们的向导将始终强制跳转到当前活动步骤。这意味着向导提供了一个browserDefault,它返回默认步骤而不是将向导作为视图渲染。这允许我们使用步骤作为视图和适配器(例如菜单实现使用的)的适配器选择器。向导像一个调度器一样跳转到正确的步骤,而不是作为一个视图本身。
>>> personWizard = PersonWizard(person, request) >>> personWizard.__parent__ = person >>> personWizard.__name__ = u'wizard'
现在从向导获取默认视图(步骤)参数。
>>> obj, names = personWizard.browserDefault(request) >>> obj <PersonWizard 'wizard'>>>> names ('person',)
现在跳转到步骤,更新并渲染它。
>>> personStep = obj.publishTraverse(request, names[0]) >>> personStep.update() >>> print(personStep.render()) <div class="wizard"> <div class="header">Person Wizard</div> <div class="wizardMenu"> <span class="selected"> <span>Person</span> </span> <span> <a href="http://127.0.0.1/person/wizard/address">Address</a> </span> </div> <form action="http://127.0.0.1" method="post" enctype="multipart/form-data" class="edit-form" id="form" name="form"> <div class="viewspace"> <div class="label">Person</div> <div class="required-info"> <span class="required">*</span>– required </div> <div class="step"> <div id="form-widgets-firstName-row" class="row required"> <div class="label"> <label for="form-widgets-firstName"> <span>First Name</span> <span class="required">*</span> </label> </div> <div class="widget"> <input id="form-widgets-firstName" name="form.widgets.firstName" class="text-widget required textline-field" value="" type="text" /> </div> </div> <div id="form-widgets-lastName-row" class="row required"> <div class="label"> <label for="form-widgets-lastName"> <span>Last Name</span> <span class="required">*</span> </label> </div> <div class="widget"> <input id="form-widgets-lastName" name="form.widgets.lastName" class="text-widget required textline-field" value="" type="text" /> </div> </div> </div> <div> <div class="buttons"> <span class="back"> </span> <span class="step"> <input id="form-buttons-apply" name="form.buttons.apply" class="submit-widget button-field" value="Apply" type="submit" /> </span> <span class="forward"> <input id="form-buttons-next" name="form.buttons.next" class="submit-widget button-field" value="Next" type="submit" /> </span> </div> </div> </div> </form> </div>
如果我们没有完成第一个步骤,我们不能进入下一个步骤。
>>> request = TestRequest(form={'form.buttons.next': 'Next'}) >>> alsoProvides(request, IDivFormLayer) >>> personWizard = PersonWizard(person, request) >>> personWizard.__parent__ = person >>> personWizard.__name__ = u'wizard' >>> personStep = personWizard.publishTraverse(request, names[0]) >>> personStep.update() >>> print(personStep.render()) <div class="wizard"> ... <div class="summary">There were some errors.</div> ... <div class="error">Required input is missing.</div> ... <div class="error">Required input is missing.</div> ...
如果我们填写了必需的值并点击下一步,我们可以完成这个步骤。
>>> request = TestRequest(form={'form.widgets.firstName': u'Roger', ... 'form.widgets.lastName': u'Ineichen', ... 'form.buttons.next': 'Next'}) >>> alsoProvides(request, IDivFormLayer) >>> personWizard = PersonWizard(person, request) >>> personWizard.__parent__ = person >>> personWizard.__name__ = u'wizard' >>> personStep = personWizard.publishTraverse(request, names[0]) >>> personStep.update() >>> print(personStep.render())
正如你所看到的,步骤被处理,向导将使用响应重定向概念重定向到下一个步骤。
>>> personWizard.nextURL 'http://127.0.0.1/person/wizard/address'
让我们使用遍历器访问下一个步骤。这将设置下一个步骤。
>>> request = TestRequest() >>> alsoProvides(request, IDivFormLayer) >>> personWizard = PersonWizard(person, request) >>> personWizard.__parent__ = person >>> personWizard.__name__ = u'wizard'
正如你所看到的,我们看到我们的下一个步骤是地址步骤。
>>> addressStep = personWizard.publishTraverse(request, 'address') >>> addressStep <AddressStep 'address'>
更新并渲染它。
>>> addressStep.update() >>> print(addressStep.render()) <div class="wizard"> <div class="header">Person Wizard</div> <div class="wizardMenu"> <span> <a href="http://127.0.0.1/person/wizard/person">Person</a> </span> <span class="selected"> <span>Address</span> </span> </div> <form action="http://127.0.0.1" method="post" enctype="multipart/form-data" class="edit-form" id="form" name="form"> <div class="viewspace"> <div class="label">Address</div> <div class="required-info"> <span class="required">*</span>– required </div> <div class="step"> <div id="form-widgets-street-row" class="row required"> <div class="label"> <label for="form-widgets-street"> <span>Street</span> <span class="required">*</span> </label> </div> <div class="widget"> <input id="form-widgets-street" name="form.widgets.street" class="text-widget required textline-field" value="" type="text" /> </div> </div> <div id="form-widgets-city-row" class="row required"> <div class="label"> <label for="form-widgets-city"> <span>City</span> <span class="required">*</span> </label> </div> <div class="widget"> <input id="form-widgets-city" name="form.widgets.city" class="text-widget required textline-field" value="" type="text" /> </div> </div> </div> <div> <div class="buttons"> <span class="back"> <input id="form-buttons-back" name="form.buttons.back" class="submit-widget button-field" value="Back" type="submit" /> </span> <span class="step"> <input id="form-buttons-apply" name="form.buttons.apply" class="submit-widget button-field" value="Apply" type="submit" /> </span> <span class="forward"> </span> </div> </div> </div> </form> </div>
向导和步骤指令
展示如何使用wizard和wizardStep指令。注册指令的元配置。
>>> import sys >>> from zope.configuration import xmlconfig >>> import z3c.wizard >>> context = xmlconfig.file('meta.zcml', z3c.wizard)
我们还需要一个自定义向导类。
>>> import z3c.wizard >>> class MyWizard(z3c.wizard.wizard.Wizard): ... """Custom wizard"""
使它们在假包custom下可用。
>>> sys.modules['custom'] = type( ... 'Module', (), ... {'MyWizard': MyWizard})()
在指令中注册向导,使用最少的属性。
>>> context = xmlconfig.string(""" ... <configure ... xmlns:z3c="http://namespaces.zope.org/z3c"> ... <z3c:wizard ... name="wizard" ... class="custom.MyWizard" ... permission="zope.Public" ... /> ... </configure> ... """, context)
现在定义一个步骤。
>>> import z3c.wizard >>> class FirstStep(z3c.wizard.step.Step): ... """First step"""
在自定义模块中注册新的步骤类。
>>> sys.modules['custom'].FirstStep = FirstStep
并在wizardStep指令中使用它们。
>>> context = xmlconfig.string(""" ... <configure ... xmlns:z3c="http://namespaces.zope.org/z3c"> ... <z3c:wizardStep ... name="first" ... wizard="custom.MyWizard" ... class="custom.FirstStep" ... permission="zope.Public" ... /> ... </configure> ... """, context)
让我们获取向导。
>>> import zope.component >>> from zope.publisher.browser import TestRequest >>> wizard = zope.component.queryMultiAdapter((object(), TestRequest()), ... name='wizard')
并检查它。
>>> wizard <MyWizard 'wizard'>>>> z3c.wizard.interfaces.IWizard.providedBy(wizard) True
让我们获取向导步骤。
>>> import zope.component >>> from zope.publisher.browser import TestRequest >>> firstStep = zope.component.queryMultiAdapter( ... (object(), TestRequest(), wizard), name='first')
并检查它。
>>> firstStep <FirstStep 'first'>>>> firstStep.context <object object at ...>>>> firstStep.wizard <MyWizard 'wizard'>>>> z3c.wizard.interfaces.IStep.providedBy(firstStep) True>>> z3c.wizard.interfaces.IWizard.providedBy(firstStep.wizard) True
清理自定义模块。
>>> del sys.modules['custom']
变更日志
2.0 (2023-02-10)
添加对Python 3.8、3.9、3.10、3.11的支持。
放弃对Python 2.7、3.4、3.5、3.6的支持。
1.1 (2019-01-27)
添加对Python 3.7的支持。
1.0 (2017-06-16)
添加对Python 3.4至3.6、PyPy2和PyPy3的支持。
0.9.1 (2011-10-28)
使用Python的doctest模块代替已废弃的zope.testing.doctest。
允许在步骤完成检查中,值在上下文中不存在。这与z3c.form处理不存在值的方式一致。
0.9.0 (2009-12-29)
在测试中避免使用z3c.form.testing:它依赖于lxml,但这里不需要lxml的功能。
使用 requiredInfo 属性来渲染必填字段的详细信息。此属性返回一个 i18n 消息 ID,使信息可翻译。
0.8.0 (2009-11-30)
调整了依赖项,反映了 zope 包中的更改:使用新包并跳过对 zope.app.publisher 的依赖。
0.7.1 (2009-10-27)
修复了 z3c.form 2.2.0 中的错误。从步骤类中删除了名称定义。这将防止基于 z3c.form 更改而出现错误。
0.7.0 (2009-08-15)
在步骤模板中添加了对字段组的支持。(从 z3c.formui 复制过来。)
有两个名为 header 的金属定义槽。将第一个重命名为 wizard-header。
0.6.0 (2009-07-10)
删除对 z3c.i18n 的依赖,因为它实际上并没有被使用,并且我们可以轻松地为“z3c”域重新创建一个消息工厂。
修复了测试,使其与 z3c.form 2.0 一起工作。
在 long_description 中添加了另一个 doctest。
将软件包的邮件列表地址更改为 zope-dev at zope.org,而不是已退休的 zope3-dev。
0.5.0 (2009-02-22)
初始发布
项目详情
下载文件
下载适合您平台的应用程序。如果您不确定选择哪个,请了解有关 安装包 的更多信息。
源分布
构建分布
z3c.wizard-2.0.tar.gz 的散列值
算法 | 散列摘要 | |
---|---|---|
SHA256 | 6c14bc5761406cad3fac0560f13295b62ee2fd09ffa04f0714d1ab35dc088def |
|
MD5 | e1161de79b615f7eb81d12bcaf2ef037 |
|
BLAKE2b-256 | 7af3639a612383bea7409bcec5227740348ffa56a9b552afdaae2cbaa97b6f41 |
z3c.wizard-2.0-py3-none-any.whl 的散列值
算法 | 散列摘要 | |
---|---|---|
SHA256 | f77c773b6cf17193e15b81d0ec5de4bc8f760eaf8e73ba035a998ded13e67082 |
|
MD5 | 00aba1c51575dabc655183201eeea42b |
|
BLAKE2b-256 | 85994c1cbdcbba74f1feef6dffa55a72d9dae069f745dc67d3d7c7b56acf8f41 |