Creating forms with megrok.z3cform ********************************** :Author: timo Purpose ------- There are different ways to create forms in Grok. The z3c.form form building framework provides a flexible and powerful way to create forms. You can find the code for this tutorial here: http://svn.zope.org/repos/main/grokapps/tutorialmegrokz3cform/trunk/ Prerequisities -------------- Before we can start to create forms, we need to create a grok project with the necessary dependencies. Creating a Grok Project:: grokproject tutorialmegrokz3cform Adding megrok.z3cform package Dependencies to our Buildout Since the megrok.z3cform.* packages are not officially released yet, we use mr.developer to automatically check out the packages from the Zope Subversion repository. We do this by adding the following lines to our buildout.cfg, right after the "versions=versions" line: buildout.cfg:: [buildout] ... versions = versions extensions += mr.developer auto-checkout = megrok.z3cform.base megrok.z3cform.layout [versions] z3c.pagelet = 1.0.3 [sources] megrok.z3cform.base = svn http://svn.zope.org/repos/main/megrok.z3cform.base/trunk megrok.z3cform.layout = svn http://svn.zope.org/repos/main/megrok.z3cform.layout/trunk # do "bin/develop up -v" to update all the checkouts ... We also want to use megrok.layout in order for our layout, so we add it to the package dependecies of our setup.py: setup.py:: install_requires=[... # Add extra requirements here ... 'megrok.layout', 'megrok.z3cform.base', 'megrok.z3cform.layout', ], Run buildout to fetch the dependencies:: $ bin/buildout Creating the Form ----------------- After creating the initial package, we can start to build our application by defining an interface. We will build a very simple database application to store contacts. Creating an Interface ===================== We define an interface for a contact with a subject and a text field. interfaces.py:: import os import zope.interface import zope.schema class IContact(zope.interface.Interface): """A z3c.form contact form.""" name = zope.schema.TextLine( title=u'Name', description=u'Name of the person.', required=True) description = zope.schema.TextLine( title=u'Description', description=u'Description of the person', required=True) Creating a Contact Class ======================== Now we create a contact class that implements the interface we just defined. contact.py:: import grok import persistent import zope.interface from zope.schema import fieldproperty from examplemegrokz3cform import interfaces class Contact(grok.Model): grok.implements(interfaces.IContact) name = fieldproperty.FieldProperty(interfaces.IContact['name']) description = fieldproperty.FieldProperty(interfaces.IContact['description']) def __init__(self, name, description): self.name = name self.description = description Creating Forms ============== Now we can create add, edit, and display forms for our contact class. browser.py:: import grok import megrok.z3cform.base import contact import interfaces import datetime from z3c.form import field, form, button, widget from examplemegrokz3cform.app import Examplemegrokz3cform from grokcore.component import global_adapter from z3c.form.interfaces import IAddForm class ContactAddForm(megrok.z3cform.base.PageAddForm): """ A sample add form.""" grok.context(Examplemegrokz3cform) label = u'Contact Add Form' fields = field.Fields(interfaces.IContact) def create(self, data): return contact.Contact(**data) def add(self, object): count = 0 while 'contact-%i' %count in self.context: count += 1; self._name = 'contact-%i' %count self.context[self._name] = object return object def nextURL(self): return self.redirect(self.url(self.context[self._name])) class ContactEditForm(megrok.z3cform.base.PageEditForm): grok.context(contact.Contact) grok.name('edit.html') form.extends(form.EditForm) label = u'Contact Edit Form' fields = field.Fields(interfaces.IContact) @button.buttonAndHandler(u'Apply and View', name='applyView') def handleApplyView(self, action): self.handleApply(self, action) if not self.widgets.errors: self.redirect(self.url(self.context, name='index')) class ContactDisplayForm(megrok.z3cform.base.PageDisplayForm): """ A simple Display Form""" grok.context(contact.Contact) grok.name('index') template = grok.PageTemplateFile('display.pt') fields = field.Fields(interfaces.IContact) We have to add a default form layer, otherwise you will get a ComponentLookupError. (Why is this? Anyone?) configure.zcml::