Skip to main content

A set of initial UI components for z3c.form.

Project description

This package provides a set of default layouts for the z3c.form framework. In particular it provides a DIV-based and a TABLE-based layout. The developer can use either layout by inheriting from a different base layer.

The package also has some support for layout/pagelet templates.

Form User Interfaces

This package provides several useful templates to get a quick start with the z3c.form package. Previous form frameworks always included default templates that were implemented in a particular user-interface development pattern. If you wanted to use an alternative strategy to develop user interfaces, it was often tedious to do so. This package aims to provide some options without requiring them for the basic framework.

Layout Template Support

One common pattern in Zope 3 user interface development is the use of layout templates (see z3c.template). This package provides some mixin classes to the regular form classes to support layout-based templating.

>>> from z3c.form import testing
>>> testing.setupFormDefaults()

Before we can start writing forms, we must have the content to work with:

>>> import zope.interface
>>> import zope.schema
>>> class IPerson(zope.interface.Interface):
...
...     name = zope.schema.TextLine(
...         title='Name',
...         required=True)
...
...     age = zope.schema.Int(
...         title='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)

Okay, that should suffice for now. Let’s now create a working add form:

>>> 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'

Let’s create a request:

>>> from z3c.form.testing import TestRequest
>>> from zope.interface import alsoProvides
>>> divRequest = TestRequest()

And support the div form layer for our request:

>>> from z3c.formui.interfaces import IDivFormLayer
>>> alsoProvides(divRequest, IDivFormLayer)

Now create the form:

>>> addForm = PersonAddForm(root, divRequest)

Since we have not specified a template yet, we have to do this now. We use our div based form template:

>>> 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')

Now register the form (content) template:

>>> import zope.interface
>>> import zope.component
>>> from z3c.template.interfaces import IContentTemplate
>>> zope.component.provideAdapter(divFormFactory,
...     (zope.interface.Interface, IDivFormLayer),
...     IContentTemplate)

And let’s define a layout template which simply calls the render method. For a more advanced content/layout render concept see 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)

Now we can get our layout template:

>>> layout = zope.component.getMultiAdapter((addForm, divRequest),
...     ILayoutTemplate)
>>> layout.__class__.__name__
'ViewPageTemplateFile'
>>> os.path.basename(layout.filename)
'myLayout.pt'

DIV-based Layout

Let’s now render the page. Note the output doesn’t contain the layout template:

>>> 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>

But we can call our form which uses the new layout template which renders the form within the div-form content template:

>>> 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>

Table-based Forms

There is a table based layout too. Let’s define the template and use them:

>>> 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')

Now register the form (content) template:

>>> zope.component.provideAdapter(tableFormFactory,
...     (zope.interface.Interface, ITableFormLayer), IContentTemplate)

Patch the request and call the form again:

>>> tableRequest = TestRequest()
>>> alsoProvides(tableRequest, ITableFormLayer)

Now our new request should know the table based form template:

>>> 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 rendering for IAdding

The z3c.formui package also provides a layout-aware version of z3c.form.adding.AddForm which can be used for creating forms for the zope.app.container.interfaces.IAdding mechanism.

Let’s check its template support. First, create the form for an Adding instance. We just need to define the create() method, because the default add() and nextURL() methods are already defined using the Adding object.

>>> from z3c.formui import adding
>>> class AddingPersonAddForm(adding.AddForm):
...
...     fields = field.Fields(IPerson)
...
...     def create(self, data):
...         return Person(**data)

Let’s now instantiate the “fake” adding component and the add form:

>>> class Adding(object):
...     def __init__(self, context, request):
...         self.context = context
...         self.request = request
>>> rootAdding = Adding(root, divRequest)
>>> addForm = AddingPersonAddForm(rootAdding, divRequest)

First, let’s ensure that we can lookup a layout template for the form:

>>> layout = zope.component.getMultiAdapter(
...     (addForm, divRequest), ILayoutTemplate)
>>> layout.__class__.__name__
'ViewPageTemplateFile'

Okay, that worked. Let’s now render the div-based addform:

>>> 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>

Okay, now we are going to check table layout support.

>>> rootAdding = Adding(root, tableRequest)
>>> addForm = AddingPersonAddForm(rootAdding, tableRequest)

Again, the layout should be available:

>>> layout = zope.component.getMultiAdapter((addForm, tableRequest),
...     ILayoutTemplate)
>>> layout.__class__.__name__
'ViewPageTemplateFile'

Let’s now render the 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>
        <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>

Form Macros

Load the configuration, which will make sure that all macros get registered correctly:

>>> 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

Create some dummy form discriminators for calling div layout templates and macros and check the 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'

We offer the following named 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

There is one generic layout template to build sub forms:

>>> objects = (form.DisplayForm(None, None), divRequest)
>>> zope.component.getMultiAdapter(objects, ILayoutTemplate,
...     'subform').filename
'...subform-layout.pt'

Div layout macros

We have different form macros available for IInputForm:

>>> from z3c.macro.interfaces import IMacroTemplate
>>> objects = (None, addForm, divRequest)
>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'form')
[...div-form.pt'), ...metal:define-macro': 'form'...
>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'subform')
[...div-form.pt'), ...define-macro': 'subform'...
>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'form-label')
[...div-form.pt'), ...define-macro': 'label'...
>>> zope.component.getMultiAdapter(
...     objects, IMacroTemplate, 'form-required-info')
[...div-form.pt'), ...define-macro', 'required-info'...
>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'form-header')
[...div-form.pt'), ...define-macro': 'header'...
>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'form-errors')
[...div-form.pt'), ...define-macro': 'errors'...
>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'widget-rows')
[...div-form.pt'), ...define-macro': 'widget-rows'...
>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'widget-row')
[...div-form.pt'), ...define-macro': 'widget-row'...
>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'form-groups')
[...div-form.pt'), ...define-macro': 'groups'...
>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'form-buttons')
[...div-form.pt'), ...define-macro', 'buttons'...

And we have different form macros available for IDisplayForm:

>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'subform-display')
[...div-form-display.pt'), ...define-macro': 'subform-display'...

Table IContentTemplate

Create some dummy form discriminators for calling table layout templates and macros and check the 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'

We offer the following named 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

There is one generic layout template to build sub forms:

>>> objects = (form.DisplayForm(None, None), tableRequest)
>>> zope.component.getMultiAdapter(objects, ILayoutTemplate,
...     'subform').filename
'...subform-layout.pt'

Table layout macros

We have different form macros available for IInputForm:

>>> objects = (None, addForm, tableRequest)
>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'form')
[...table-form.pt'), ...metal:define-macro': 'form'...
>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'subform')
[...table-form.pt'), ...define-macro': 'subform'...
>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'form-label')
[...table-form.pt'), ...define-macro': 'label'...
>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'form-required-info')
[...table-form.pt'), ...define-macro', 'required-info'...
>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'form-header')
[...table-form.pt'), ...define-macro': 'header'...
>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'form-errors')
[...table-form.pt'), ...define-macro': 'errors'...
>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'form-table')
[...table-form.pt'), ...define-macro', 'formtable'...
>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'form-row')
[...table-form.pt'), ...define-macro': 'formrow'...
>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'form-label-cell')
[...table-form.pt'), ...define-macro', 'labelcell'...
>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'form-widget-cell')
[...table-form.pt'), ...define-macro', 'widgetcell'...
>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'form-groups')
[...table-form.pt'), ...define-macro': 'groups'...
>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'form-buttons')
[...table-form.pt'), ...define-macro', 'buttons'...

And we have different form macros available for IDisplayForm:

>>> zope.component.getMultiAdapter(objects, IMacroTemplate, 'subform-display')
[...table-form-display.pt'), ...define-macro': 'subform-display'...

Subform

Let’s give a quick overview how subform content and layout templates get used: First define a new form which uses the template getter methods offered from z3.template

>>> from z3c.template.template import getPageTemplate, getLayoutTemplate

The provider TALES expression which is a part of the lookup concept was already registered by the testing setup, so we don’t need to do it here.

and the TALES expression called macro which can lookup our macro adapters. Yes, macros are adapters in our content/layout template concept. See z3c.macro for more information about the implementation. However, we already registered the macro type in the testing setup, as it’s needed for rendering form templates.

and at least we need a pagelet renderer. By default we use the provider called PageletRenderer defined in the z3c.pagelet package. But right now, we don’t have a dependency on this package. So let’s implement a simple renderer and use them as a 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')

Now define the form:

>>> class PersonEditForm(form.EditForm):
...     """Edit form including layout support. See z3c.formui.form."""
...
...     template = getPageTemplate('subform')
...     layout = getLayoutTemplate('subform')
...
...     fields = field.Fields(IPerson)

Now we can render the form with our previous created person instance:

>>> person = Person('Jessy', 6)
>>> editForm = PersonEditForm(person, divRequest)

Now we call the form which will update and render it:

>>> 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>

You can see that the form above is a real subform. It doesn’t define the form tag which makes it usable as a subform in parent forms.

Of course this works with table layout based forms too. Let’s use our table request and render the form again:

>>> 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>

Redirection

The form doesn’t bother rendering itself and its layout when request is a redirection as the rendering doesn’t make any sense with browser requests in that case. Let’s create a view that does a redirection in its update method:

>>> class RedirectingView(PersonEditForm):
...     def update(self):
...         super(RedirectingView, self).update()
...         self.request.response.redirect('.')

It will return an empty string when called as a browser page.

>>> redirectView = RedirectingView(person, divRequest)
>>> redirectView() == ''
True

However, the render method will render form’s template as usual:

>>> '<div class="viewspace">' in redirectView.render()
True

The same thing should work for AddForms:

>>> class RedirectingAddView(PersonAddForm):
...     def update(self):
...         super(RedirectingAddView, self).update()
...         self.request.response.redirect('.')
>>> redirectView = RedirectingAddView(person, divRequest)
>>> redirectView() == ''
True

No required fields

If there no required fields in the form, standard templates won’t render the “required-info” hint.

>>> class IAdditionalInfo(zope.interface.Interface):
...
...     location = zope.schema.TextLine(title='Location', required=False)
...     about = zope.schema.Text(title='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

Cleanup

>>> import shutil
>>> shutil.rmtree(temp_dir)

CHANGES

4.1 (2024-10-22)

  • Add support for Python 3.12, 3.13.

  • Drop support for Python 3.7.

4.0 (2023-02-24)

  • Drop support for Python 2.7, 3.4, 3.5, 3.6.

  • Add support for Python 3.8, 3.9, 3.10, 3.11.

3.1 (2018-11-15)

  • Add support for Python 3.4, 3.5, 3.6, 3.7.

  • Drop support for Python 2.6 and 3.3.

3.0.0 (2015-11-09)

  • Standardize namespace __init__

  • Split config, mostly to be able to include in pyramid without browser resources and viewlets

3.0.0a2 (2013-02-26)

  • Added missing version Trove classifiers.

3.0.0a1 (2013-02-25)

  • Added support for Python 3.3.

  • Dropped support for Python 2.4 and 2.5.

2.3.0 (2012-03-15)

  • Feature: Mark a widget row with the “required” class when the widget is required. Similarly, when the widget has an error attached, add the “error” class to the widget row. That allows you to change the styles of the label and the widget if it is reuqired.

2.2.1 (2012-01-09)

  • No longer using deprecated zope.testing.doctest but built-in doctest instead.

  • Fixed tests so they do not break for z3c.form 2.5.0.

2.2.0 (2009-12-28)

  • Fixed tests so they do not break for z3c.form 2.2.0.

  • Using requiredInfo property (introduced in z3c.form 2.0.0) to render the information about required fields. This property returns an i18n message id making the information translateable.

  • Added support for groups containing groups: They get displayed now.

2.1.0 (2009-09-01)

  • Feature: Don’t show required info hint if there’s no required fields.

  • Bug: Don’t render add forms when redirecting as well.

  • Bug: Fix redirection tests with newer zope.publisher that restricts untrusted redirects to different domains.

2.0.0 (2009-06-14)

  • Feature: Added support for context-specific template lookup, introduced in z3c.template 1.2.0 - templates can now be registered using (view, request, context) discriminator.

  • Feature: Added support for z3c.pt templates using z3c.ptcompat compatibility package.

  • Feature: Added layout support for IAdding component based add forms.

  • Feature: Added CSS for multi-widget which was added in z3c.form 2.0.0.

  • Bug: Changed usage of template/macros/* to macro:*, because the first one doesn’t work when we override a form template and use the form macro, registered with this package.

  • Bug: Don’t do rendering in form’s __call__ method when request is a redirection.

  • Bug: Reformatted long-description to render properly on pypi.

1.4.2 (2008-08-26)

  • Bug: Corrected typos and unwanted unicode characters.

1.4.1 (2008-01-23)

  • Bug: Fixed up meta-data and the release.

1.4.0 (2008-01-21)

  • Feature: Added subform content and layout template. This allows you to configure real sub forms which do not render the form tag.

  • Feature: Improve layout implementation, support built-in layout templates.

  • Feature: Use IContentTemplate instead of IPageTemplate in layout base classes. This will help to prevent running into recursion errors if there is a missing layout template.

  • Feature: Added form module which offers built-in layout support.

  • Bug: Added missing display IContentTemplate, otherwise we can run into a recursion in some cases.

  • Bug: Renamed table macro argument from form-required-info to required-info. The macro form-required-info did not exist.

  • Bug: Added unit tests for layout support.

  • Bug: Added tests for layout macros.

  • Bug: Added tests for layout templates.

1.3.0 (2007-08-24)

  • Refactoring: Update CSS classes to reflect latest changes to the widget classes in z3c.form.

  • Bug: Error view snippets may have a empty widget attribute values, so we cannot rely on accessing the label of the widget. This is the case, if the error view sniipet was created from an invariants validation error.

  • Bug: The table-form template did not properly render the error at the widget, because the render() method was not called. Thanks to Markus Leist for the report.

1.2.0 (2007-07-18)

  • Feature: The row div element now also has an id of the form “<widget-id>-row”.

1.1.1 (2007-07-04)

  • Refactoring: Split up registrations for simpler management of UI components. This also makes it easier to see for developers how to create a new template for forms.

1.1.0 (2007-06-29)

  • Feature: Registered all defined macros for each form template. Also, added more slots to the templates providing more hooks for customization.

  • Feature: Added a macro/slot for the “required info”, which explains how required fields are marked.

  • Feature: Added support for form labels.

  • Feature: Added support for groups to templates.

1.0.1 (2007-06-22)

  • Bug: Make sure we use the id for the “for” attribute of the “label” element and not the name. This has worked until recently, because the name and id were the same, but they are different now.

1.0.0 (2007-05-24)

  • Initial Release

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

z3c.formui-4.1.tar.gz (33.9 kB view details)

Uploaded Source

Built Distribution

z3c.formui-4.1-py3-none-any.whl (30.7 kB view details)

Uploaded Python 3

File details

Details for the file z3c.formui-4.1.tar.gz.

File metadata

  • Download URL: z3c.formui-4.1.tar.gz
  • Upload date:
  • Size: 33.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.11.10

File hashes

Hashes for z3c.formui-4.1.tar.gz
Algorithm Hash digest
SHA256 982762ab7b5aa5473706c057b0a667e799b65068a30f68d00dbf980d28dcc613
MD5 64f20065da498241618bc8ad2c1fd45e
BLAKE2b-256 3125137165cd69dfd55c71211024cacd8429043a7d0ed75bc88f20913adab61c

See more details on using hashes here.

File details

Details for the file z3c.formui-4.1-py3-none-any.whl.

File metadata

  • Download URL: z3c.formui-4.1-py3-none-any.whl
  • Upload date:
  • Size: 30.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.11.10

File hashes

Hashes for z3c.formui-4.1-py3-none-any.whl
Algorithm Hash digest
SHA256 0c62848fb344a6e2ab2c8eed367d13328185970d7a001d7d12ef6b7608b1a6f3
MD5 e8eeb89ea3a9ebdb5957585d3d1c1478
BLAKE2b-256 8d0df7d49880b0fa114b2bdca78623ed542870774048b5a923318a2d03504428

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page