Why do we want to do that in first place? Lets consider an use-case where we get loginid and user's name from an
The zope.schema allows us to set a property named
Let's see its implementation using Grok
AddForm
. But, in EditForm
we don't want the user to change the login ID. One way to implement this, is to, omit the loginid field in the edit form's form_fields
attribute. Suppose we want to display the loginid as read only field in EditForm
alone, then we need to manipulate the schema field's default properties.
from zope import interface, schema
class IUser(interface.Interface):
loginid = schema.BytesLine(title=u"Login ID", required=True)
name = schema.TextLine(title=u"User name", required=True)
The zope.schema allows us to set a property named
readonly
to schema fields in the interface. For our case, if we specify them in the interface we can't be able to get the loginid from the user in AddForm
. So, we are going to manipulate this at runtime in EditForm
.
Let's see its implementation using Grok
import grok
class EditUser(grok.EditForm):
grok.context(IUser)
grok.name('edit')
form_fields = grok.AutoFields(IUser)
def setUpWidgets(self, ignore_request=False):
# This method is responsible for constructing the widgets from
# form_fields. So, we override this method to manipulate the
# schema field
self.form_fields['loginid'].field.readonly = True
super(EditUser, self).setUpWidgets(ignore_request)
# Once we change the field's properties, its effect will be
# seen across forms. i.e even the AddForm after viewing an
# EditForm will have the 'loginid' as readonly field. So, we
# revert them back to their originals
self.form_fields['loginid'].field.readonly = False
@grok.action('Save')
def edit(self, **data):
self.applyData(self.context, **data)
self.redirect(self.url(self.context.__parent__, 'list'))