跳转到主要内容

Zope3的即用层

项目描述

此软件包提供基于z3c.form和z3c.pagelet的层。此层可用于自定义皮肤。

为Zope 3准备的层

此软件包包含ready2go层。此层支持正确的一组组件注册,并可用于自定义皮肤中的继承。

重要

此层支持z3c.pageletz3c.form模式。这意味着每个页面,例如错误页面,都是基于z3c.pagelet概念。默认情况下,我们使用基于<div>的布局用于z3c表单。

IReady2GoBrowserLayer

ready2go层对于在没有访问ZMI菜单(如zmi_views等)的情况下构建自定义表示层非常有用。这意味着如果您使用此层,则没有注册菜单项。

有关此层提供的更多信息,请参阅 z3c.layer.pagelet

测试

为测试 IReady2GoBrowserLayer 层,我们使用测试包中定义的测试皮肤,该皮肤使用 IReady2GoBrowserLayer 层作为唯一的基本层。这意味着,我们的测试皮肤只提供最小包中定义的视图以及测试中定义的测试视图。

首先登录为管理员

>>> from webtest.app import TestApp
>>> manager = TestApp(
...     make_wsgi_app(), extra_environ={
...         'wsgi.handleErrors': False,
...         'HTTP_AUTHORIZATION': 'Basic mgr:mgrpw'})
>>> err_manager = TestApp(
...     make_wsgi_app(), extra_environ={
...         'HTTP_AUTHORIZATION': 'Basic mgr:mgrpw'})

检查我们是否可以使用我们的皮肤访问在 ftesting.zcml 文件中注册的 page.html 视图

>>> skinURL = 'https://127.0.0.1/++skin++Ready2GoTestSkin'
>>> res = manager.get(skinURL + '/page.html')
>>> res.request.url
'https://127.0.0.1/++skin++Ready2GoTestSkin/page.html'

页面组件支持

检查我们是否可以访问来自 z3c.layer.pagelet ftesting.zcml 配置的测试页面。

>>> print(res.html) #doctest: +PARSE_HTML
<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>PageletTestLayout</title>
</head>
<body>
  test page
</body>
</html>

未找到

现在检查未找到页面,这是一个在 zope.publisher.interfaces.INotFound 异常上的异常视图

>>> manager.get(skinURL + '/foobar.html')
Traceback (most recent call last):
...
NotFound: Object: <zope.site.folder.Folder ...>, name: 'foobar.html'
>>> res = err_manager.get(skinURL + '/foobar.html', status=404)
>>> print(res.html)
<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>PageletTestLayout</title>
</head>
<body>
  <div>
  <br />
  <br />
  <h3>
    The page you are trying to access is not available
  </h3>
  <br />
  <b>
    Please try the following:
  </b>
  <br />
  <ol>
    <li>
      Make sure that the Web site address is spelled correctly.
    </li>
    <li>
      <a href="javascript:history.back(1);">
        Go back and try another URL.
      </a>
    </li>
  </ol>
</div>
</body>
</html>

用户错误

并检查为 zope.exceptions.interfaces.IUserError 异常注册的用户错误页面

>>> res = err_manager.get(skinURL + '/@@usererror.html')
>>> print(res.html)
<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>PageletTestLayout</title>
</head>
<body>
  <div>
  <div>simply user error</div>
</div>
</body>
</html>

常见异常(系统错误)

并检查注册用于 zope.interface.common.interfaces.IException 的错误视图

>>> res = err_manager.get(skinURL + '/@@systemerror.html', status=500)
>>> print(res.html)
<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>PageletTestLayout</title>
</head>
<body>
  <div>
  <br />
  <br />
  <h3>A system error occurred</h3>
  <br />
  <b>Please contact the administrator.</b>
  <a href="javascript:history.back(1);">
    Go back and try another URL.
  </a>
</div>
</body>
</html>

禁止 403

并检查 zope.security.interfaces.IUnauthorized 视图,为此使用一个新未注册的用户(测试浏览器)。

>>> unauthorized = TestApp(make_wsgi_app())
>>> unauthorized.get(skinURL + '/@@forbidden.html')
Traceback (most recent call last):
...
AppError: Bad response: 403 Forbidden
>>> res = unauthorized.get(skinURL + '/@@forbidden.html', status=403)
>>> print(res.html)
<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>PageletTestLayout</title>
</head>
<body>
  <div>
  <br />
  <br />
  <h3>Unauthorized</h3>
  <br />
  <b>You are not authorized.</b>
</div>
</body>
</html>

如您所见,此测试将返回一个 403 禁止错误。但这仅仅是因为我们没有可用的未认证主体。请参阅下面的测试,了解如果我们注册一个未认证主体会发生什么。

未授权 401

如果我们使用认证主体并访问被禁止的页面,我们将得到一个 401 未授权而不是 403 禁止错误页面。

>>> from zope.configuration import xmlconfig
>>> import zope.principalregistry
>>> def zcml(s):
...     context = xmlconfig.file('meta.zcml', zope.principalregistry)
...     xmlconfig.string(s, context)
>>> zcml("""
...    <configure
...        xmlns="http://namespaces.zope.org/zope"
...        >
...
...      <unauthenticatedPrincipal
...         id="zope.unknown"
...         title="Anonymous user"
...         description="A person we don't know"
...         />
...
...    </configure>
... """)
>>> manager2 = TestApp(make_wsgi_app(), extra_environ={
...         'wsgi.handleErrors': True})
>>> res = manager2.get(skinURL + '/@@forbidden.html')
Traceback (most recent call last):
...
AppError: Bad response: 401 Unauthorized
>>> res = manager2.get(skinURL + '/@@forbidden.html', status=401)
>>> print(res.html)
<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>PageletTestLayout</title>
</head>
<body>
  <div>
  <br />
  <br />
  <h3>Unauthorized</h3>
  <br />
  <b>You are not authorized.</b>
</div>
</body>
</html>

表单和表单布局支持

此层还提供了来自 z3c.formui 的表单宏。让我们创建一个简单的表单

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

在我们可以开始编写表单之前,我们必须有要处理的内容

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

好吧,现在应该足够了。现在让我们创建一个工作添加表单

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

现在创建表单

>>> root = getRootFolder()
>>> 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
<zope.browserpage.viewpagetemplatefile.ViewPageTemplateFile object at ...>

基于DIV的布局

现在让我们渲染页面。注意输出不包含布局模板

>>> addForm.update()
>>> print(addForm.render())
<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="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 id="form-widgets-name" name="form.widgets.name"
                 class="text-widget required textline-field"
                 value="" type="text" />
        </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 id="form-widgets-age" name="form.widgets.age"
                 class="text-widget int-field"
                 value="20" type="text" />
        </div>
      </div>
    </div>
  </div>
  <div>
    <div class="buttons">
      <input id="form-buttons-add" name="form.buttons.add"
             class="submit-widget button-field" value="Add" type="submit" />
    </div>
  </div>
</form>

表单宏

至少尝试加载配置,这将确保所有宏都正确注册。

>>> from zope.configuration import xmlconfig
>>> import zope.component
>>> import zope.security
>>> import zope.viewlet
>>> import zope.browserpage
>>> import zope.browserresource
>>> import z3c.macro
>>> import z3c.template
>>> import z3c.formui
>>> xmlconfig.XMLConfig('meta.zcml', zope.browserpage)()
>>> xmlconfig.XMLConfig('meta.zcml', zope.browserresource)()
>>> xmlconfig.XMLConfig('meta.zcml', zope.component)()
>>> xmlconfig.XMLConfig('meta.zcml', zope.security)()
>>> xmlconfig.XMLConfig('meta.zcml', zope.viewlet)()
>>> xmlconfig.XMLConfig('meta.zcml', z3c.macro)()
>>> xmlconfig.XMLConfig('meta.zcml', z3c.template)()
>>> xmlconfig.XMLConfig('configure.zcml', z3c.formui)()

Div布局宏

现在我们可以看到我们有不同的表单宏可用

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

清理

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

变更日志

2.0 (2023-02-08)

  • 放弃对 Python 2.7、3.5、3.6 的支持。

  • 添加对 Python 3.7、3.8、3.9、3.10、3.11 的支持。

  • 放弃通过 python setup.py test 运行测试的过时支持。

1.0.0 (2017-04-17)

  • 将 Python 支持固定在 2.7、3.5、3.6 和 PyPy 上。

1.0.0a1 (2013-03-03)

  • 添加对 Python 3.3 的支持。

  • zope.testbrowser 测试更改为 WebTest,因为 zope.testbrowser 尚未移植。

  • 将过时的 zope.interface.implements 使用替换为等效的 zope.interface.implementer 装饰器。

  • 放弃对 Python 2.4 和 2.5 的支持。

  • 修复测试设置和测试,以便在当前版本的必需包上运行。

0.6.0 (2009-12-01)

  • 调整依赖关系,跳过对 zope.app.publisherzope.app.http 的依赖关系,并在 Zope 包中反映这些更改。

0.5.3 (2009-07-24)

  • 修复测试以与最新包一起工作。

0.5.2 (2009-02-19)

  • 不再依赖于过时的 z3c.viewlet

  • 修复测试以与当前的 z3c.form 一起运行。

  • 修复 long_description 以在 pypi 上正确渲染。

0.5.1 (2008-01-24)

  • 错误:修复元数据。

0.5.0 (2008-01-21)

  • 初始发布

项目详细信息


下载文件

下载适用于您平台的文件。如果您不确定该选择哪个,请了解更多关于安装包的信息。

源分发

z3c.layer.ready2go-2.0.tar.gz (20.0 kB 查看哈希值)

上传时间

构建分发

z3c.layer.ready2go-2.0-py3-none-any.whl (16.9 kB 查看哈希值)

上传时间 Python 3