Grok is not allowed for Plone core developement. Grok is not recommended for Plone addon development.
Using Grok framework in Plone programming. Grok provides Dont-Repeat-Yourself API to create Zope 3 components easier.
- Using Grok in your package
- Plone 4.3 migration and five.grok dependency
- Grok static media folder
- Creating a viewlet using Grok
- Creating a viewlet manager: Grok way
- More info
Grok is a project to give sane, easy to use, API to Zope 3 systems. It exists as standalone, but Plone compatible port five.grok is available for Plone 3.3 and onwards.
Benefits over using pure Zope 3 APIs
- No ZCML files or XML sit-ups needed (except bootstrapping one configure.zcml file)
- More things are automatic and less explicit hand-written code needed. E.g. template file and view class are automatically matched.
- Less code generation
Grok will automatically scan all .py files in your product and run registration code in them. This way you can use Python decorators and magical classes to perform tasks which before needed to have hand written registration code.
To enable grok'ing for your package:
- The top-level
configure.zcmlmust include the
groknamespace and the
grok:grokdirective. You do not need to put this directive subpackages. This directive scans your package source tree recursively for grok'ed files.
- The package must be loaded using
setup.pyauto-include, NOT using a
zcml =section in
buildout.cfg. Otherwise templates are not loaded.
- Optionally, add
staticfolders to your package root.
- You still need to include subpackages for old-fashioned ZCML configurations.
<configure xmlns="http://namespaces.zope.org/zope" xmlns:five="http://namespaces.zope.org/five" xmlns:cmf="http://namespaces.zope.org/cmf" xmlns:i18n="http://namespaces.zope.org/i18n" xmlns:grok="http://namespaces.zope.org/grok" i18n_domain="plonetheme.xxx"> <include package="five.grok" /> <five:registerPackage package="." initialize=".initialize" /> <!-- Grok the package to initialise schema interfaces and content classes --> <grok:grok package="." /> <include package=".browser" /> </configure>
If you are using components from other packages you might also want to add
<includeDependencies package="." />
This makes the
configure.zcml and thus Python code
of all modules listed in
section is loaded before your module is being processed.
You still need to get
five.grok package to your buildout.
Edit your Python egg
setup.py file and list
five.grok as dependency:
install_requires = ["five.grok", ...],
Re-run buildout. Now buildout should download
five.grok for PyPi and activate it for you.
If you are using Plone 4.1 or older you also need Dexterity extends = line pindowns in your buildout. Otherwise you may get Version Conflict errors when running buildout.
Please see Plone 4.2 -> 4.3 Dexterity upgrade guide first.
Plone 4.3 ships with Dexterity.
five.grok is a huge dependency with a lot of
code of which maintenance cannot be guaranteed in the future (See grok.zope.org,
Because Plone community cannot commit to maintain this code, but we still want to use the best goodies
of grok based development, some compromises was made for Plone 4.3 regarding grok style forms and directives.
- You can include
five.grokas a dependency, as you have done this far, but it is not going to be in Plone default installation in foreseeable future. Please see migration notes.
grok.name()in classes are not supported by Plone 4.3 out of the box
plone.directives.formgoodies distributed to two supported packages:
To make your code Plone 4.3 compatible, grokless way do imports as following:
import z3c.form.form from plone.supermodel import model from plone.autoform import directives as form from plone.autoform.form import AutoExtensibleForm
And you can use them like:
class IChoiceExamples(model.Schema): """ Single choice and multiple choice examples """ form.widget(multiChoiceCheckbox=CheckBoxFieldWidget) multiChoiceCheckbox = zope.schema.List( title=u"Checkbox multiple choices", ...) # Different form base classes are provided: # XXX: Fill in here what you should use with Dexterity content types class ChoiceExamples(AutoExtensibleForm, z3c.form.form.Form): """ """ schema = IChoiceExamples
If you further want to break the dependency with
and get rid of
grok.xxx() directives in your classes
here are further dependency.
five.grok from the dependency list of your egg and remove
<grok:grok> ZCML directive in
from five import grok in all of your package modules.
Declare views and forms using
grok.templatedir() and map view classes to templates using
<browser:page> ZCML directive.
Grok migration source example:
class Demos(grok.View): """ Render all demo forms with their widgets in a nice view. Read forms which implements IWidgetDemo marke via @widget_demo class decocator. Build a nice and useful description string for each field in those forms. """ grok.context(ISiteRoot) grok.name("widgets-demo")
configuration.zcml target example:
<configure xmlns="http://namespaces.zope.org/zope" xmlns:five="http://namespaces.zope.org/five" xmlns:cmf="http://namespaces.zope.org/cmf" xmlns:i18n="http://namespaces.zope.org/i18n" xmlns:browser="http://namespaces.zope.org/browser" i18n_domain="plone.app.widgets"> <browser:page name="widgets-demo" for="Products.CMFCore.interfaces.ISiteRoot" class=".demo.Demos" permission="zope2.View" template="widgets-demo.pt" /> </configure>
update() themselves - this concerns only non-form views
If your view has
update() method you need to call it manually in
BrowserView base class doesn't do this.
- def update(self):
- def __call__(self):
- self.update() return self.index() # Or self.render() for grok.CodeView
Learn more about
Since five.grok 1.3.0 this method does not work.
The easiest way to manage static resources is to make use of the static resource directory feature in five.grok.
Simply add a directory called static in the package and make sure that the
<grok:grok package="." />
line appears in configure.zcml.
Example how to include
yourproduct.app/static folder as
<configure ... xmlns:grok="http://namespaces.zope.org/grok"> <grok:grok package="." /> </configure>
static resource directory in the
example.conference package contains a file called
it will be accessible on a URL like
The resource name is the same as the package name wherein the static directory appears.
Since the release of Plone 4, this (grok) method is simpler.
Example subscription which subscribes a content type to add and edit events:
from five import grok from Products.Archetypes.interfaces import IObjectEditedEvent from Products.Archetypes.interfaces import IObjectInitializedEvent class ORAResearcher(folder.ATFolder, orabase.ORABase, ResearcherMixin): """A Researcher synchronized from ORA. """ implements(IORAResearcher, IResearcher) meta_type = "ORAResearcher" schema = ORAResearcherSchema # Callbacks for both add and edit events @grok.subscribe(ORAResearcher, IObjectEditedEvent) def object_edited(context, event): orabase.object_edited(context, event) @grok.subscribe(ORAResearcher, IObjectInitializedEvent) def object_added(context, event): orabase.object_added(context, event)
Example subscription which subscribes events without context:
# Really old stuff from ZPublisher.interfaces import IPubStart # Modern stuff from five import grok @grok.subscribe(IPubStart) def check_redirect(e): """ Check if we have a custom redirect script in Zope application server root. """
For more information, see:
Grok framework allows you to register a viewlet easily using Python directives.
It is recommended that you use Dexterity ZopeSkel add-on product code skeleton where you add this code.
Then create folder
yourcomponent.app/yourcomponent/app/browser/templates where you add the related
<tal:extra-head omit-tag="" condition="viewlet/available"> <meta name="something" content="your custom meta"> </tal:extra-head>
Recommended if you want to keep the number of files and lines of XML and Python to a minimum.
An example here for related Python code:
- Add dependencies to your
buildout.cfgto include the good known version set.
- Add the
grokZCML directive to