跳转到主要内容

为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> &ndash; 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>
          &ndash; 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>
          &ndash; 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>
          &ndash; 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>
          &ndash; 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>
    &ndash; 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>
    &ndash; 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)

  • 初始版本

由以下支持