[Zope-dev] SVN: z3c.form/trunk/ ``GroupForm`` and ``Group`` now use ``getContent`` method when instantiating group classes instead of directly accessing ``self.context``, as this is the usual way to access the context of the form and allows nested groups to have a different context than the main form.
Laurent Mignon
laurent.mignon at softwareag.com
Tue Jan 19 10:58:34 EST 2010
Michael Howitz wrote:
> The motivation is the following:
>
> self.getContent() seems to be the pattern to access the context of a form. I used grep: there is no place where self.context is used directly besides in group.py. So it seems to be an error in the code not to use the common pattern.
> But after reading the doctests of z3c.form I'm no longer sure whether this is correct.
>
> My use case is the following:
>
> I have a folder with contained items. In a form I display the schema of the folder in the group form and the schemas of all contained items as groups. Each group has a nested group displaying the meta data for the group's content. As the context of the groups was the folder (group = groupClass(self.context, self.request, self)) the meta data displayed was wrong.
>
But if your Groupform override getContent to provide an object
implementing the expected interface, that's right
>> Class IAddress(Interface):
>> street = zope.schema.TextLine(
>> title='street')
>>
>> Class IPerson(Interface);
>> firstname = zope.schema.TextLine(
>> title='firstname')
>>
>> address = zope.schema.Object(
>> title='address',
>> schema = IAddress)
>>
>>
>> class Address(object):
>> implements(IAddress)
>>
>> def __init__(self, **kw):
>> for name, value in kw.items():
>> setattr(self, name, value)
>>
>>
>> class Person(object):
>> implements(IPerson)
>>
>> def __init__(self, **kw):
>> for name, value in kw.items():
>> setattr(self, name, value)
>>
>> class AddressGroup(group.Group):
>> label = 'Address'
>> fields = field.Fields(zope.schema.TextLine(
>> __name__ = 'owner',
>> title='Owner',
>> readOnly=True)
>> fields += field.Fields(IAddress).select('street')
>>
>> def getContext(self):
>
> Should be "getContent", I think.
>
>> return {
>> 'owner': self.context.firstname,
>> 'street': self.context.address.street}
>>
>> class PersonGroup(group.Group):
>> label = 'Person'
>> fields += field.Fields(IPerson).select('firstname')
>>
>>
>> class PersonEditForm(group.GroupForm, form.EditForm):
>> fields = field.Fields(zope.schema.TextLine(
>> __name__="description',
>> title='Description',
>> readOnly=True)
>> groups = (PersonGroup, AddressGroup)
>>
>> def getContent(self):
>> return {'description': 'Form used to edit a person and its
>> Address'}
>
> I had never seen this before but according to the doctests of z3c.form it is a valid use case.
My understand of ``getContent`` is to provide a way to give values used
by the widgets. By default, since the common use case is to edit /
display values from the context, the implementation return the context.
If your form has to deal with fields defined in an interface not
provided by the context, you have a lot of ways to provides the related
values.
* The first one is to provide an adapter adapting the context to the
interface defining the field
* The second one is to override the ``getContent`` implementation so
it'll return an object implementing the right interface
* The thirds one is to override the ``getContent`` implementation so
it'll return a dictionary where key = field.__name__ and value = the
value expected by the field. (In fact a default adapter exist that adapt
a dict to an interface)
* ...
Have a look to datamanager.txt....
>>
>> class MyEditForm(group.GroupForm, form.EditForm):
>>
>> def __init__(self, context, request):
>> super(MyEditForm, self).__init__(context, request)
>> firstContext = {}
>> secondContext = {}
>> self.groups = (
>> MyFirstGroup(firstcontext, request, self),
>> MySecondGroup(secondContext, request, self))
>
> I'm not sure whether this works. (I'll try it.) Whether it works it obsoletes my changes.
>
According to the z3c.form implemention, the right place to put your
subform initialization is into the ``update`` method.
class MyEditForm(group.GroupForm, form.EditForm):
def update(self):
self.groups = (
MyFirstGroup(self.context.obj1, request, self),
MySecondGroup(self.context.obj2, request, self))
super(MyEditForm,self).update()
Yours sincerely,
sagblmi
More information about the Zope-Dev
mailing list