为z3c.form提供一组初始UI组件。
项目描述
此软件包为z3c.form框架提供一组默认布局。特别是它提供基于DIV和基于表格的布局。开发者可以通过从不同的基础层继承来使用任一布局。
该软件包还提供了一些对布局/页面组件模板的支持。
表单用户界面
本包提供了一些有用的模板,以便快速开始使用 z3c.form 包。以前表单框架总是包含了特定用户界面开发模式实现的默认模板。如果您想使用替代策略开发用户界面,通常会很麻烦。本包旨在提供一些选项,而无需为基本框架强制要求。
布局模板支持
Zope 3 用户界面开发中的一个常见模式是使用布局模板(参见 z3c.template)。本包为常规表单类提供了一些混合类,以支持基于布局的模板。
>>> from z3c.form import testing >>> testing.setupFormDefaults()
在开始编写表单之前,我们必须有要处理的内容
>>> import zope.interface >>> import zope.schema >>> class IPerson(zope.interface.Interface): ... ... name = zope.schema.TextLine( ... title=u'Name', ... required=True) ... ... age = zope.schema.Int( ... title=u'Age', ... description=u"The person's age.", ... min=0, ... default=20, ... required=False)>>> from zope.schema.fieldproperty import FieldProperty >>> @zope.interface.implementer(IPerson) ... class Person(object): ... name = FieldProperty(IPerson['name']) ... age = FieldProperty(IPerson['age']) ... ... def __init__(self, name, age): ... self.name = name ... self.age = age ... ... def __repr__(self): ... return '<%s %r>' % (self.__class__.__name__, self.name)
好吧,目前应该足够了。现在让我们创建一个工作表单
>>> from z3c.form import field >>> from z3c.formui import form, layout >>> class PersonAddForm(form.AddForm): ... ... fields = field.Fields(IPerson) ... ... def create(self, data): ... return Person(**data) ... ... def add(self, object): ... self.context[object.id] = object ... ... def nextURL(self): ... return 'index.html'
让我们创建一个请求
>>> from z3c.form.testing import TestRequest >>> from zope.interface import alsoProvides >>> divRequest = TestRequest()
并支持我们的请求的 div 表单层
>>> from z3c.formui.interfaces import IDivFormLayer >>> alsoProvides(divRequest, IDivFormLayer)
现在创建表单
>>> addForm = PersonAddForm(root, divRequest)
由于我们尚未指定模板,现在必须这样做。我们使用基于 div 的表单模板
>>> import os >>> import z3c.formui >>> divFormTemplate = os.path.join(os.path.dirname(z3c.formui.__file__), ... 'div-form.pt')>>> from z3c.template.template import TemplateFactory >>> divFormFactory = TemplateFactory(divFormTemplate, 'text/html')
现在注册表单(内容)模板
>>> import zope.interface >>> import zope.component >>> from z3c.template.interfaces import IContentTemplate >>> zope.component.provideAdapter(divFormFactory, ... (zope.interface.Interface, IDivFormLayer), ... IContentTemplate)
现在让我们定义一个布局模板,它只是简单地调用渲染方法。有关更高级的内容/布局渲染概念,请参阅 z3c.pagelet。
>>> import tempfile >>> temp_dir = tempfile.mkdtemp()>>> myLayout = os.path.join(temp_dir, 'myLayout.pt') >>> with open(myLayout, 'w') as file: ... _ = file.write('''<html> ... <body> ... <tal:block content="structure view/render"> ... content ... </tal:block> ... </body> ... </html>''') >>> myLayoutFactory = TemplateFactory(myLayout, 'text/html')>>> from z3c.template.interfaces import ILayoutTemplate >>> zope.component.provideAdapter(myLayoutFactory, ... (zope.interface.Interface, zope.interface.Interface), ILayoutTemplate)
现在我们可以获取我们的布局模板
>>> layout = zope.component.getMultiAdapter((addForm, divRequest), ... ILayoutTemplate)>>> layout.__class__.__name__ 'ViewPageTemplateFile'>>> os.path.basename(layout.filename) 'myLayout.pt'
基于DIV的布局
现在让我们渲染页面。注意输出不包含布局模板
>>> addForm.update() >>> print(addForm.render()) <form action="http://127.0.0.1" method="post" enctype="multipart/form-data" class="edit-form" name="form" id="form"> <div class="viewspace"> <div class="required-info"> <span class="required">*</span> – required </div> <div> <div id="form-widgets-name-row" class="row required"> <div class="label"> <label for="form-widgets-name"> <span>Name</span> <span class="required">*</span> </label> </div> <div class="widget"><input type="text" id="form-widgets-name" name="form.widgets.name" class="text-widget required textline-field" value="" /> </div> </div> <div id="form-widgets-age-row" class="row"> <div class="label"> <label for="form-widgets-age"> <span>Age</span> </label> </div> <div class="widget"><input type="text" id="form-widgets-age" name="form.widgets.age" class="text-widget int-field" value="20" /> </div> </div> </div> </div> <div> <div class="buttons"> <input type="submit" id="form-buttons-add" name="form.buttons.add" class="submit-widget button-field" value="Add" /> </div> </div> </form>
但我们可以调用我们的表单,它使用新的布局模板,并在 div-form 内容模板中渲染表单
>>> print(addForm()) <html> <body> <form action="http://127.0.0.1" method="post" enctype="multipart/form-data" class="edit-form" name="form" id="form"> <div class="viewspace"> <div class="required-info"> <span class="required">*</span> – required </div> <div> <div id="form-widgets-name-row" class="row required"> <div class="label"> <label for="form-widgets-name"> <span>Name</span> <span class="required">*</span> </label> </div> <div class="widget"><input type="text" id="form-widgets-name" name="form.widgets.name" class="text-widget required textline-field" value="" /> </div> </div> <div id="form-widgets-age-row" class="row"> <div class="label"> <label for="form-widgets-age"> <span>Age</span> </label> </div> <div class="widget"><input type="text" id="form-widgets-age" name="form.widgets.age" class="text-widget int-field" value="20" /> </div> </div> </div> </div> <div> <div class="buttons"> <input type="submit" id="form-buttons-add" name="form.buttons.add" class="submit-widget button-field" value="Add" /> </div> </div> </form> </body> </html>
基于表格的表单
还有一个基于表格的布局。让我们定义模板并使用它们
>>> from z3c.formui.interfaces import ITableFormLayer >>> tableFormTemplate = os.path.join(os.path.dirname(z3c.formui.__file__), ... 'table-form.pt')>>> from z3c.template.template import TemplateFactory >>> tableFormFactory = TemplateFactory(tableFormTemplate, 'text/html')
现在注册表单(内容)模板
>>> zope.component.provideAdapter(tableFormFactory, ... (zope.interface.Interface, ITableFormLayer), IContentTemplate)
修补请求并再次调用表单
>>> tableRequest = TestRequest() >>> alsoProvides(tableRequest, ITableFormLayer)
现在我们的新请求应该知道基于表格的表单模板
>>> addForm = PersonAddForm(root, tableRequest) >>> print(addForm()) <html> <body> <form action="http://127.0.0.1" method="post" enctype="multipart/form-data" class="edit-form" name="form" id="form"> <div class="viewspace"> <div class="required-info"> <span class="required">*</span> – required </div> <div> <table class="form-fields"> <tr class="row required"> <td class="label"> <label for="form-widgets-name"> <span>Name</span> <span class="required"> * </span> </label> </td> <td class="field"> <div class="widget"><input type="text" id="form-widgets-name" name="form.widgets.name" class="text-widget required textline-field" value="" /> </div> </td> </tr> <tr class="row"> <td class="label"> <label for="form-widgets-age"> <span>Age</span> </label> </td> <td class="field"> <div class="widget"><input type="text" id="form-widgets-age" name="form.widgets.age" class="text-widget int-field" value="20" /> </div> </td> </tr> </table> </div> </div> <div> <div class="buttons"> <input type="submit" id="form-buttons-add" name="form.buttons.add" class="submit-widget button-field" value="Add" /> </div> </div> </form> </body> </html>
AddForm渲染为IAdding
z3c.formui 包还提供了一个布局感知版本的 z3c.form.adding.AddForm,可用于为 zope.app.container.interfaces.IAdding 机制创建表单。
让我们检查它的模板支持。首先,为 Adding 实例创建表单。我们只需要定义 create() 方法,因为默认的 add() 和 nextURL() 方法已经使用 Adding 对象定义。
>>> from z3c.formui import adding >>> class AddingPersonAddForm(adding.AddForm): ... ... fields = field.Fields(IPerson) ... ... def create(self, data): ... return Person(**data)
现在让我们实例化“假的”添加组件和表单
>>> class Adding(object): ... def __init__(self, context, request): ... self.context = context ... self.request = request >>> rootAdding = Adding(root, divRequest)>>> addForm = AddingPersonAddForm(rootAdding, divRequest)
首先,让我们确保我们可以查找表单的布局模板
>>> layout = zope.component.getMultiAdapter( ... (addForm, divRequest), ILayoutTemplate)>>> layout.__class__.__name__ 'ViewPageTemplateFile'
好的,这成功了。现在让我们渲染基于 div 的添加表单
>>> print(addForm()) <html> <body> <form action="http://127.0.0.1" method="post" enctype="multipart/form-data" class="edit-form" name="form" id="form"> <div class="viewspace"> <div class="required-info"> <span class="required">*</span> – required </div> <div> <div id="form-widgets-name-row" class="row required"> <div class="label"> <label for="form-widgets-name"> <span>Name</span> <span class="required">*</span> </label> </div> <div class="widget"><input type="text" id="form-widgets-name" name="form.widgets.name" class="text-widget required textline-field" value="" /> </div> </div> <div id="form-widgets-age-row" class="row"> <div class="label"> <label for="form-widgets-age"> <span>Age</span> </label> </div> <div class="widget"><input type="text" id="form-widgets-age" name="form.widgets.age" class="text-widget int-field" value="20" /> </div> </div> </div> </div> <div> <div class="buttons"> <input type="submit" id="form-buttons-add" name="form.buttons.add" class="submit-widget button-field" value="Add" /> </div> </div> </form> </body> </html>
好的,现在我们将检查表格布局支持。
>>> rootAdding = Adding(root, tableRequest) >>> addForm = AddingPersonAddForm(rootAdding, tableRequest)
同样,布局应该是可用的
>>> layout = zope.component.getMultiAdapter((addForm, tableRequest), ... ILayoutTemplate)>>> layout.__class__.__name__ 'ViewPageTemplateFile'
现在让我们渲染表单
>>> print(addForm()) <html> <body> <form action="http://127.0.0.1" method="post" enctype="multipart/form-data" class="edit-form" name="form" id="form"> <div class="viewspace"> <div class="required-info"> <span class="required">*</span> – required </div> <div> <table class="form-fields"> <tr class="row required"> <td class="label"> <label for="form-widgets-name"> <span>Name</span> <span class="required"> * </span> </label> </td> <td class="field"> <div class="widget"><input type="text" id="form-widgets-name" name="form.widgets.name" class="text-widget required textline-field" value="" /> </div> </td> </tr> <tr class="row"> <td class="label"> <label for="form-widgets-age"> <span>Age</span> </label> </td> <td class="field"> <div class="widget"><input type="text" id="form-widgets-age" name="form.widgets.age" class="text-widget int-field" value="20" /> </div> </td> </tr> </table> </div> </div> <div> <div class="buttons"> <input type="submit" id="form-buttons-add" name="form.buttons.add" class="submit-widget button-field" value="Add" /> </div> </div> </form> </body> </html>
表单宏
加载配置,这将确保所有宏都正确注册
>>> from zope.configuration import xmlconfig >>> import zope.component >>> import zope.viewlet >>> import zope.security >>> import zope.publisher >>> import zope.browserresource >>> import z3c.macro >>> import z3c.template >>> import z3c.formui >>> xmlconfig.XMLConfig('meta.zcml', zope.component)() >>> xmlconfig.XMLConfig('meta.zcml', zope.viewlet)() >>> xmlconfig.XMLConfig('meta.zcml', zope.security)() >>> xmlconfig.XMLConfig('meta.zcml', zope.publisher)() >>> xmlconfig.XMLConfig('meta.zcml', zope.browserresource)() >>> xmlconfig.XMLConfig('meta.zcml', z3c.macro)() >>> xmlconfig.XMLConfig('meta.zcml', z3c.template)() >>> xmlconfig.XMLConfig('configure.zcml', z3c.formui)()
Div IContentTemplate
创建一些用于调用 div 布局模板和宏的模拟表单区分符,并检查 div IContentTemplates
>>> objects = (addForm, divRequest) >>> zope.component.getMultiAdapter(objects, IContentTemplate).filename '...div-form.pt'>>> objects = (form.DisplayForm(None, None), divRequest) >>> zope.component.getMultiAdapter(objects, IContentTemplate, '').filename '...div-form-display.pt'
我们提供了以下命名 IContentTemplate
>>> objects = (form.DisplayForm(None, None), divRequest) >>> zope.component.getMultiAdapter(objects, IContentTemplate, ... 'display').filename '...div-form-display.pt'>>> objects = (form.DisplayForm(None, None), divRequest) >>> zope.component.getMultiAdapter(objects, IContentTemplate, ... 'subform').filename '...subform.pt'
Table ILayoutTemplate
有一个通用的布局模板用于构建子表单
>>> objects = (form.DisplayForm(None, None), divRequest) >>> zope.component.getMultiAdapter(objects, ILayoutTemplate, ... 'subform').filename '...subform-layout.pt'
Div布局宏
我们有不同的表单宏可用于 IInputForm
>>> from z3c.macro.interfaces import IMacroTemplate >>> objects = (None, addForm, divRequest) >>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'form') [...div-form.pt'), ...metal:define-macro': u'form'...>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'subform') [...div-form.pt'), ...define-macro': u'subform'...>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'form-label') [...div-form.pt'), ...define-macro': u'label'...>>> zope.component.getMultiAdapter( ... objects, IMacroTemplate, 'form-required-info') [...div-form.pt'), ...define-macro', u'required-info'...>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'form-header') [...div-form.pt'), ...define-macro': u'header'...>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'form-errors') [...div-form.pt'), ...define-macro': u'errors'...>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'widget-rows') [...div-form.pt'), ...define-macro': u'widget-rows'...>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'widget-row') [...div-form.pt'), ...define-macro': u'widget-row'...>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'form-groups') [...div-form.pt'), ...define-macro': u'groups'...>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'form-buttons') [...div-form.pt'), ...define-macro', u'buttons'...
并且我们有不同的表单宏可用于 IDisplayForm
>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'subform-display') [...div-form-display.pt'), ...define-macro': u'subform-display'...
Table IContentTemplate
创建一些用于调用表格布局模板和宏的模拟表单区分符,并检查 div IContentTemplates
>>> objects = (addForm, tableRequest) >>> zope.component.getMultiAdapter(objects, IContentTemplate, '').filename '...table-form.pt'>>> objects = (form.DisplayForm(None, None), tableRequest) >>> zope.component.getMultiAdapter(objects, IContentTemplate, '').filename '...table-form-display.pt'
我们提供了以下命名 IContentTemplate
>>> objects = (form.DisplayForm(None, None), tableRequest) >>> zope.component.getMultiAdapter(objects, IContentTemplate, ... 'display').filename '...table-form-display.pt'>>> objects = (form.DisplayForm(None, None), tableRequest) >>> zope.component.getMultiAdapter(objects, IContentTemplate, ... 'subform').filename '...subform.pt'
Table ILayoutTemplate
有一个通用的布局模板用于构建子表单
>>> objects = (form.DisplayForm(None, None), tableRequest) >>> zope.component.getMultiAdapter(objects, ILayoutTemplate, ... 'subform').filename '...subform-layout.pt'
表格布局宏
我们有不同的表单宏可用于 IInputForm
>>> objects = (None, addForm, tableRequest) >>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'form') [...table-form.pt'), ...metal:define-macro': u'form'...>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'subform') [...table-form.pt'), ...define-macro': u'subform'...>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'form-label') [...table-form.pt'), ...define-macro': u'label'...>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'form-required-info') [...table-form.pt'), ...define-macro', u'required-info'...>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'form-header') [...table-form.pt'), ...define-macro': u'header'...>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'form-errors') [...table-form.pt'), ...define-macro': u'errors'...>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'form-table') [...table-form.pt'), ...define-macro', u'formtable'...>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'form-row') [...table-form.pt'), ...define-macro': u'formrow'...>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'form-label-cell') [...table-form.pt'), ...define-macro', u'labelcell'...>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'form-widget-cell') [...table-form.pt'), ...define-macro', u'widgetcell'...>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'form-groups') [...table-form.pt'), ...define-macro': u'groups'...>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'form-buttons') [...table-form.pt'), ...define-macro', u'buttons'...
并且我们有不同的表单宏可用于 IDisplayForm
>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'subform-display') [...table-form-display.pt'), ...define-macro': u'subform-display'...
子表单
让我们快速概述一下子表单内容和布局模板的使用方法:首先定义一个新的表单,它使用 z3.template 提供的模板获取方法
>>> from z3c.template.template import getPageTemplate, getLayoutTemplate
作为查找概念的组成部分的 provider TALES 表达式已经由测试设置注册,所以这里不需要做。
以及名为 macro 的 TALES 表达式,它可以查找我们的宏适配器。是的,宏是我们内容/布局模板概念中的适配器。有关实现信息,请参阅 z3c.macro。然而,我们已经在前面的测试设置中注册了 macro 类型,因为它是渲染表单模板所必需的。
至少我们需要一个页面组件渲染器。默认情况下,我们使用在 z3c.pagelet 包中定义的名为 PageletRenderer 的提供者。但现在,我们没有这个包的依赖。所以让我们实现一个简单的渲染器,并作为 IContentProvider 使用它们。
>>> class PageletRenderer(object): ... zope.component.adapts(zope.interface.Interface, ... zope.publisher.interfaces.browser.IBrowserRequest, ... zope.interface.Interface) ... ... def __init__(self, context, request, pagelet): ... self.__updated = False ... self.__parent__ = pagelet ... self.context = context ... self.request = request ... ... def update(self): ... pass ... ... def render(self): ... return self.__parent__.render()>>> from zope.contentprovider.interfaces import IContentProvider >>> zope.component.provideAdapter(PageletRenderer, ... provides=IContentProvider, name='pagelet')
现在定义表单
>>> class PersonEditForm(form.EditForm): ... """Edit form including layout support. See z3c.formui.form.""" ... ... template = getPageTemplate('subform') ... layout = getLayoutTemplate('subform') ... ... fields = field.Fields(IPerson)
现在我们可以使用之前创建的人实例来渲染表单
>>> person = Person(u'Jessy', 6) >>> editForm = PersonEditForm(person, divRequest)
现在调用表单,它会更新并渲染它
>>> print(editForm()) <div class="viewspace"> <div class="required-info"> <span class="required">*</span> – required </div> <div> <div id="form-widgets-name-row" class="row required"> <div class="label"> <label for="form-widgets-name"> <span>Name</span> <span class="required">*</span> </label> </div> <div class="widget"><input type="text" id="form-widgets-name" name="form.widgets.name" class="text-widget required textline-field" value="Jessy" /> </div> </div> <div id="form-widgets-age-row" class="row"> <div class="label"> <label for="form-widgets-age"> <span>Age</span> </label> </div> <div class="widget"><input type="text" id="form-widgets-age" name="form.widgets.age" class="text-widget int-field" value="6" /> </div> </div> </div> </div> <div> <div class="buttons"> <input type="submit" id="form-buttons-apply" name="form.buttons.apply" class="submit-widget button-field" value="Apply" /> </div> </div>
你可以看到上面的表单是一个真正的子表单。它没有定义表单标签,这使得它可以作为父表单中的子表单使用。
当然,这也适用于基于表格布局的表单。让我们使用我们的表格请求再次渲染表单
>>> editForm = PersonEditForm(person, tableRequest) >>> print(editForm()) <div class="viewspace"> <div class="required-info"> <span class="required">*</span> – required </div> <div> <table class="form-fields"> <tr class="row required"> <td class="label"> <label for="form-widgets-name"> <span>Name</span> <span class="required"> * </span> </label> </td> <td class="field"> <div class="widget"><input type="text" id="form-widgets-name" name="form.widgets.name" class="text-widget required textline-field" value="Jessy" /> </div> </td> </tr> <tr class="row"> <td class="label"> <label for="form-widgets-age"> <span>Age</span> </label> </td> <td class="field"> <div class="widget"><input type="text" id="form-widgets-age" name="form.widgets.age" class="text-widget int-field" value="6" /> </div> </td> </tr> </table> </div> </div> <div> <div class="buttons"> <input type="submit" id="form-buttons-apply" name="form.buttons.apply" class="submit-widget button-field" value="Apply" /> </div> </div>
重定向
表单不会在请求是重定向时麻烦地渲染自身及其布局,因为在这种情况下渲染没有意义。让我们创建一个视图,在它的更新方法中进行重定向
>>> class RedirectingView(PersonEditForm): ... def update(self): ... super(RedirectingView, self).update() ... self.request.response.redirect('.')
当作为浏览器页面调用时,它将返回一个空字符串。
>>> redirectView = RedirectingView(person, divRequest) >>> redirectView() == '' True
然而,render 方法将像往常一样渲染表单模板
>>> '<div class="viewspace">' in redirectView.render() True
同样的事情也应该适用于添加表单
>>> class RedirectingAddView(PersonAddForm): ... def update(self): ... super(RedirectingAddView, self).update() ... self.request.response.redirect('.') >>> redirectView = RedirectingAddView(person, divRequest) >>> redirectView() == '' True
无必填字段
如果表单中没有必填字段,标准模板不会渲染“必填信息”提示。
>>> class IAdditionalInfo(zope.interface.Interface): ... ... location = zope.schema.TextLine(title=u'Location', required=False) ... about = zope.schema.Text(title=u'About', required=False)>>> class AdditionalInfoForm(form.AddForm): ... ... fields = field.Fields(IAdditionalInfo)>>> additionalInfoForm = AdditionalInfoForm(root, divRequest) >>> additionalInfoForm.update() >>> '<div class="required-info">' in additionalInfoForm.render() False>>> additionalInfoForm = AdditionalInfoForm(root, tableRequest) >>> additionalInfoForm.update() >>> '<div class="required-info">' in additionalInfoForm.render() False
清理
>>> import shutil >>> shutil.rmtree(temp_dir)
CHANGES
4.0 (2023-02-24)
停止支持 Python 2.7、3.4、3.5、3.6。
添加对 Python 3.8、3.9、3.10、3.11 的支持。
3.1 (2018-11-15)
添加对 Python 3.4、3.5、3.6、3.7 的支持。
停止支持 Python 2.6 和 3.3。
3.0.0 (2015-11-09)
标准化命名空间 __init__
分割配置,主要是为了能够在 pyramid 中包含没有浏览器资源和视图组件
3.0.0a2 (2013-02-26)
添加了缺少的 Trove 类别器。
3.0.0a1 (2013-02-25)
添加了对 Python 3.3 的支持。
停止支持 Python 2.4 和 2.5。
2.3.0 (2012-03-15)
特性:当小部件是必填项时,使用“required”类标记小部件行。同样,当小部件附加了错误时,向小部件行添加“error”类。这允许你更改标签和小部件的样式,如果它是必填项。
2.2.1 (2012-01-09)
不再使用已弃用的 zope.testing.doctest,而是使用内置的 doctest。
修复了测试,以便它们不会在 z3c.form 2.5.0 中中断。
2.2.0 (2009-12-28)
修复了测试,以便它们不会在 z3c.form 2.2.0 中中断。
使用 requiredInfo 属性(在 z3c.form 2.0.0 中引入)来渲染关于必填字段的说明。此属性返回一个 i18n 消息 ID,使信息可翻译。
添加了对包含组的组的支持:它们现在将显示出来。
2.1.0 (2009-09-01)
特性:如果没有必填字段,则不显示必填信息提示。
错误:在重定向时也不渲染添加表单。
错误:修复了使用较新的 zope.publisher(它将不受信任的重定向限制为不同域名)的重定向测试。
2.0.0 (2009-06-14)
特性:添加了对 z3c.template 1.2.0 中引入的上下文特定模板查找的支持 - 现在可以使用(视图、请求、上下文)辨别器注册模板。
特性:添加了对使用 z3c.ptcompat 兼容包的 z3c.pt 模板的支持。
特性:添加了对基于 IAdding 组件的添加表单的布局支持。
特性:添加了对在 z3c.form 2.0.0 中添加的多小部件的 CSS 支持。
错误:将 template/macros/* 的用法更改为 macro:*,因为第一个在覆盖表单模板并使用此包注册的表单宏时不起作用。
错误:当请求是重定向时,不要在表单的 __call__ 方法中执行渲染。
错误:重新格式化长描述,以便在 pypi 上正确渲染。
1.4.2 (2008-08-26)
错误:更正了拼写错误和不需要的 Unicode 字符。
1.4.1 (2008-01-23)
错误:修复了元数据和发布。
1.4.0 (2008-01-21)
特性:添加了子表单内容和布局模板。这允许您配置不渲染表单标签的实际子表单。
特性:改进布局实现,支持内置布局模板。
特性:在布局基类中使用IContentTemplate代替IPageTemplate。这有助于防止在缺少布局模板时遇到递归错误。
特性:添加了表单模块,它提供内置布局支持。
错误:添加了缺失的显示IContentTemplate,否则在某些情况下可能会遇到递归。
错误:将表宏参数从form-required-info重命名为required-info。宏form-required-info不存在。
错误:为布局支持添加了单元测试。
错误:为布局宏添加了测试。
错误:为布局模板添加了测试。
1.3.0 (2007-08-24)
重构:更新CSS类以反映z3c.form中小部件类的最新更改。
错误:错误视图片段可能具有空的widget属性值,因此我们不能依赖于访问小部件的标签。如果是从不变性验证错误创建的错误视图片段,就会发生这种情况。
错误:表单模板没有正确渲染小部件中的错误,因为没有调用render()方法。感谢Markus Leist的报告。
1.2.0 (2007-07-18)
特性:行div元素现在也有表单“<widget-id>-row”的id。
1.1.1 (2007-07-04)
重构:拆分注册以简化UI组件的管理。这也使开发者更容易了解如何为表单创建新模板。
1.1.0 (2007-06-29)
特性:为每个表单模板注册所有定义的宏。还向模板添加了更多插槽,以提供更多自定义钩子。
特性:添加了“必填信息”的宏/插槽,解释了如何标记必填字段。
特性:添加了对表单标签的支持。
特性:添加了对模板中组的支持。
1.0.1 (2007-06-22)
错误:确保我们使用id作为“label”元素的“for”属性,而不是name。这直到最近一直有效,因为name和id相同,但现在它们不同了。
1.0.0 (2007-05-24)
初始版本
z3c.formui-4.0.tar.gz的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 855777a94713cdc628cff0f10f190246acedb28e4aac1ab7085d1aec71f92ad9 |
|
MD5 | 2abed35a29737de11b69bf29010a952f |
|
BLAKE2b-256 | 553b59414e3ff83e403b072591d03e22ee5a437f2c2720a2cbc7f85e3547f8d2 |
z3c.formui-4.0-py3-none-any.whl的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 67f2348c44b20242ec53a38dd2cf3876250a84a84defadb41de087c73b8f1532 |
|
MD5 | bc35cfc8c1ec80106fac87da1eedd410 |
|
BLAKE2b-256 | fca817e83b688d303a7fd4f0624d036fccd4f91ebf85dda88fb99d812d282abf |