makina corpus在plone上使用grok magic的z3cform的一个小集成。
collective.z3cform.grok的Python项目详细描述
Introduction
This package enables the use of z3c forms in grok.View style inside a plone environment.
Note that you have two wrappers and a basic form class:
- FormWrapper to use the basic ^{tt1}$ template
- PloneFormWrapper is a basic z3c.form wrapper with some plone integration (fieldsets & kss) (from ^{tt2}$)
- PloneForm is a basic z3c.form with some plone integration (fieldsets & groups) (from plone.app.z3cform)
- A TestCase to test your code with z3cform.grok with either using directly itself or by sublassing it
Basic Usage
在“foo.py”模块中声明表单
>>> import plone.z3cform.fieldsets.extensible.ExtensibleForm$ >>> import z3c.form.form.Form >>> class Myform(plone.z3cform.fieldsets.extensible.ExtensibleForm, z3c.form.form.Form): ... """A z3c.form""" ... ingoreContext = True or False # override me
注意collective.z3cform.grok.grok.PloneForm是前一个声明的快捷方式,请参见实现。
然后是包装纸
>>> from collective.z3cform.grok.grok import PloneFormWrapper >>> class myview(PloneFormWrapper): ... form = Myform
在foo_templates/myview.py中编写一个基本模板,例如:
<tal metal:use-macro="context/main_template/macros/master"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:tal="http://xml.zope.org/namespaces/tal" xmlns:metal="http://xml.zope.org/namespaces/metal" xmlns:i18n="http://xml.zope.org/namespaces/i18n" i18n:domain="nmd.sugar.forms" xml:lang="en" lang="en" tal:define="lang language" tal:attributes="lang lang; xml:lang lang"> <body> <metal:main fill-slot="body"> <tal:block tal:content="structure python:view.render_form()"></tal:block> </metal:main> </body> </html> </tal>
等等,您可以访问您的表单@
Basic grok testing in a third party package
导入基本测试用例
>>> from collective.z3cform.grok.tests.test_doctests import DocTestCase as dt >>> from collective.z3cform.grok.tests.test_doctests import collective_z3cform_grok_setUp >>> from collective.z3cform.grok.tests.test_doctests import collective_z3cform_grok_tearDown
用您最喜欢的测试用例之一编写测试用例
>>> class DocTestCase(MyFunctionalTestCase, dt): ... def setUp_hook(self, *args, **kwargs): ... MyFunctionalTestCase.setUp(self) ... def tearDown_hook(self, *args, **kwargs): ... MyFunctionalTestCase.tearDown(self) ... def afterSetUp(self): ... """.""" ... MyFunctionalTestCase.afterSetUp(self) ...
制作一个doc_suite soap组合整体
>>> def test_doctests_suite(directory=None, globs=None, suite=None, testklass=None): ... if not testklass: testklass=DocTestCase ... if not directory: ... directory, _f = os.path.split(os.path.abspath(__file__)) ... elif os.path.isfile(directory): ... directory = os.path.dirname(directory) ... files = [os.path.join(directory, f) for f in os.listdir(directory) ... if f.endswith('.txt')] ... if not globs: ... globs={} ... g = globals() ... for key in g: ... globs.setdefault(key, g[key]) ... directory = directory ... ... if not suite: ... suite = unittest.TestSuite() ... if files: ... options = doctest.REPORT_ONLY_FIRST_FAILURE |\ ... doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS ... for test in files: ... ft = ztc.ZopeDocFileSuite( ... test, ... test_class=testklass, ... optionflags=options, ... globs=globs, ... setUp=collective_z3cform_grok_setUp, ... tearDown=collective_z3cform_grok_tearDown, ... module_relative = False, ... ) ... suite.addTest(ft) ... return suite >>> def test_suite(): ... """.""" ... suite = unittest.TestSuite() ... return test_doctests_suite(suite=suite) Et voila, all files ending with txt in the tests directory will be tested with that magic TestCase.
Using grok.View to display z3c.forms in plone
这个包的目标是使z3c.form和plone的集成最小化。 与plone.app.directive相去甚远,我的目标是轻装上阵。
做一个简单的命名模式
<<< import collective;from five import grok <<< import zope, z3c <<< class IMyFormSchema(zope.interface.Interface): ... name = zope.schema.Text(title=u"Name", description = u'Name', required=False) <<< class MyForm(z3c.form.form.Form): ... ignoreContext = True ... fields = z3c.form.field.Fields(IMyFormSchema) ... @z3c.form.button.buttonAndHandler(u'Ok', name='Ok') ... def ok(self, action, *args, **kwargs): ... msg = u'me Grok NameField <> @name == %s' % self.widgets['name'].value ... from Products.statusmessages.interfaces import IStatusMessage ... IStatusMessage(self.request).addStatusMessage(msg, type='info')
grok.view包装表单可以是这样的
<<< class myview(collective.z3cform.grok.grok.FormWrapper): ... grok.context(zope.interface.Interface) ... form = MyForm
请注意,这个grok样式的类支持这些属性:
- layer: the Form Layer
- Any grok directive (require, template, context, etc.)
- form: The form class
- Think that you can add some directives also on your form like ignoreContext
- 我们知道grok是如何工作的,告诉我们想要一个作为上下文的接口,这个表单适用于任何地方。
- ignoreContext仅用于删除上下文映射。
- 我们现在要做的就是实例化并呈现我们的视图和表单。 使用grok magic,视图已经在我们的门户上注册了 注意,它的模板将自动解析为module_templates/lower_view_name.pt,这里是:form_templates/bar.bt
>>> request = make_request() >>> interface.alsoProvides(request, z3c.form.interfaces.IFormLayer) >>> interface.alsoProvides(request, zope.annotation.interfaces.IAttributeAnnotatable) >>> pv = getMultiAdapter((portal, request), name='myview') >>> pv.template.__grok_location__.endswith('form_templates/myview.pt') True >>> print open(pv.template.__grok_location__).read() <html xmlns="http://www.w3.org/1999/xhtml" xmlns:tal="http://xml.zope.org/namespaces/tal" xmlns:metal="http://xml.zope.org/namespaces/metal" xmlns:i18n="http://xml.zope.org/namespaces/i18n" lang="en" xml:lang="en" metal:use-macro="context/main_template/macros/master"> <body> <metal:main fill-slot="main"> <tal:main-macro metal:define-macro="main"> <p>my grokky template</p> <p>The form is:</p> <tal:block tal:content="structure python:view.render_form()"></tal:block> </tal:main-macro> </metal:main> </body> </html> <BLANKLINE>
我们需要调用update方法来手动触发form.update()进程
>>> pv.compute_widgets() >>> print '\n'.join([a.rstrip() for a in pv.render_form().split('\n') if a.strip()]) <form action="http://nohost/@@myview" method="post" enctype="multipart/form-data"> <div class="row"> <div class="field"> <label for="form-widgets-name"> <span>Name</span> </label> <div class="formHelp">Name</div> <div class="widget"> <textarea id="form-widgets-name" name="form.widgets.name" class="textarea-widget text-field"></textarea> </div> </div> </div> <div class="action"> <input type="submit" id="form-buttons-Ok" name="form.buttons.Ok" class="submit-widget button-field" value="Ok" /> </div> </form> >>> pv.__class__ <class 'collective.z3cform.grok.tests.form.myview'>
验证grok.view的真实性
>>> from zope.interface.verify import verifyObject >>> from grokcore.view.interfaces import IGrokView >>> pv.request is request True >>> verifyObject(IGrokView, pv) True
我们还可以通过web测试所有内容是否就绪,我们的视图是否已注册,并且switch_oncruft是否正常工作。注意,它使用plone.app.z3cformform.pt模板。
>>> browser.open(portal.absolute_url()+"/@@myview") >>> print '\n'.join([a.rstrip() for a in browser.contents.split('\n') if a.strip()]) <...<p>my grokky template</p>...<p>The form is:</p> ...<p class="discreet"></p> ...<form class="rowlike enableUnloadProtection kssattr-formname-@@myview"...action="http://nohost/plone/@@myview"... ...id="form-widgets-name"... ...id="form-buttons-Ok"... ...</form>...
测试表单提交和操作是否有效
>>> browser.handleErrors = False >>> browser.open(portal.absolute_url()+"/@@myview") >>> browser.getControl(name='form.widgets.name').value = 'foo' >>> browser.getControl(name='form.buttons.Ok').click() >>> browser.url 'http://nohost/plone/@@myview' >>> 'class="textarea-widget text-field">foo</textarea>' in browser.contents True
使用先前请求设置的StatusMessage cookie再次打开
>>> '<dd>me Grok NameField <> @name == foo</dd>' in browser.contents True
collective.z3cform.grok Installation
要将collective.z3cform.grok安装到全局python环境(或workingenv)中, 使用传统的zope 2实例,您可以这样做:
When you’re reading this you have probably already run ^{tt9}$. Find out how to install setuptools (and EasyInstall) here: http://peak.telecommunity.com/DevCenter/EasyInstall
If you are using Zope 2.9 (not 2.10), get pythonproducts and install it via:
python setup.py install --home /path/to/instanceinto your Zope instance.
Create a file called ^{tt10}$ in the ^{tt11}$ directory. The file should only contain this:
<include package="collective.z3cform.grok" />
或者,如果您使用的是zc.buildout和plone.recipe.zope2instance 配方管理您的项目,您可以这样做:
Add ^{tt12}$ to the list of eggs to install, e.g.:
[buildout] ... eggs = ... collective.z3cform.grokTell the plone.recipe.zope2instance recipe to install a ZCML slug:
[instance] recipe = plone.recipe.zope2instance ... zcml = collective.z3cform.grokRe-run buildout, e.g. with:
$ ./bin/buildout
如果要显式地包含包,可以跳过zcml slug 从另一个包的configure.zcml文件。
Changelog
1.15 (2012-08-08)
- fix utf-8 header
- fix interfaces import
- remove useless dependencies
- changed plone.z3cform.z2.decode in grok.py to reflect the existing plone.z3cform - maybe was a version difference [miohtama]
1.10
- Add other forms helpers (contextless, subform)
- Externalize some glue to deal with zope2 requests for reuse in other code.
1.9
- remove useless call
1.6 - 1.7 - 1.8
- rework the tests infra.
1.4-1.5
- fix packaing & reload function
1.3
- add plone form
- yet better support for layers
1.2
- handle better group forms and layers
1.1
- bugfix: misunderstood something about the form.updateWidgets method.
1.0
- Initial release