Re: [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.
Hi, I doesn't understand the motivation behind this change and I've the feeling that it'll break some existing code.... May be am I wrong but ``getContent`` method is used to provides values to widgets and actions as described into the interface: '''Return the content to be displayed and/or edited.''' Why do you want to give the content to the subform. Providing the wright content according to its definition is under the subform responsability. If not overrided, it's true that ``getContent`` return by default the context. But for me the fact that you give the result of a call to getContent as context for groupForm will break the following code: 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): 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'} person = Person(firstname='fName', address=Address(street='street')) request = testing.TestRequest() edit = PersonEditForm(person, request) Before the changes the previous 'not tested' code worked as expected. Since you give the result of getContent when instantiating the SubForms, This code is now broken and I've to modify the getContent method on each subfoms to take the context on the parentForm pointer. 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): return { 'owner': self.parentForm.context.firstname, 'street': self.parentform.context.address.street} As I've said, may be am I wrong but I've the feeling that using the ``getContent`` as context for a subform introduce a mismatch between the 2 concepts behind ``context`` and ``getContent`` and can break existing code. The same result can be achieved, by explicitly instantiating the subforms into the parentForm constructor. 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)) Regards, sagblmi Michael Howitz wrote:
Log message for revision 108077: ``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.
Changed: U z3c.form/trunk/CHANGES.txt U z3c.form/trunk/src/z3c/form/group.py
-=- Modified: z3c.form/trunk/CHANGES.txt =================================================================== --- z3c.form/trunk/CHANGES.txt 2010-01-12 16:55:11 UTC (rev 108076) +++ z3c.form/trunk/CHANGES.txt 2010-01-12 17:33:51 UTC (rev 108077) @@ -5,7 +5,9 @@ 2.3.1 (unreleased) ------------------
-- Nothing changed yet. +- ``GroupForm`` and ``Group`` now use ``getContent`` method when + instantiating group classes instead of directly accessing + ``self.context``.
2.3.0 (2009-12-28)
Modified: z3c.form/trunk/src/z3c/form/group.py =================================================================== --- z3c.form/trunk/src/z3c/form/group.py 2010-01-12 16:55:11 UTC (rev 108076) +++ z3c.form/trunk/src/z3c/form/group.py 2010-01-12 17:33:51 UTC (rev 108077) @@ -52,7 +52,7 @@ if interfaces.IGroup.providedBy(groupClass): group = groupClass else: - group = groupClass(self.context, self.request, self) + group = groupClass(self.getContent(), self.request, self) group.update() groups.append(group) self.groups = tuple(groups) @@ -130,7 +130,7 @@ if interfaces.IGroup.providedBy(groupClass): group = groupClass else: - group = groupClass(self.context, self.request, self) + group = groupClass(self.getContent(), self.request, self) group.update() groups.append(group) self.groups = tuple(groups)
Am 19.01.2010 um 09:44 schrieb Laurent Mignon:
Hi,
I doesn't understand the motivation behind this change and I've the feeling that it'll break some existing code....
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.
May be am I wrong but ``getContent`` method is used to provides values to widgets and actions as described into the interface: '''Return the content to be displayed and/or edited.''' Why do you want to give the content to the subform. Providing the wright content according to its definition is under the subform responsability.
If not overrided, it's true that ``getContent`` return by default the context. But for me the fact that you give the result of a call to getContent as context for groupForm will break the following code:
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.
person = Person(firstname='fName', address=Address(street='street')) request = testing.TestRequest()
edit = PersonEditForm(person, request)
Before the changes the previous 'not tested' code worked as expected. Since you give the result of getContent when instantiating the SubForms, This code is now broken and I've to modify the getContent method on each subfoms to take the context on the parentForm pointer.
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): return { 'owner': self.parentForm.context.firstname, 'street': self.parentform.context.address.street}
As I've said, may be am I wrong but I've the feeling that using the ``getContent`` as context for a subform introduce a mismatch between the 2 concepts behind ``context`` and ``getContent`` and can break existing code. The same result can be achieved, by explicitly instantiating the subforms into the parentForm constructor.
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.
Michael Howitz wrote:
Log message for revision 108077: ``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.
Changed: U z3c.form/trunk/CHANGES.txt U z3c.form/trunk/src/z3c/form/group.py
-=- Modified: z3c.form/trunk/CHANGES.txt =================================================================== --- z3c.form/trunk/CHANGES.txt 2010-01-12 16:55:11 UTC (rev 108076) +++ z3c.form/trunk/CHANGES.txt 2010-01-12 17:33:51 UTC (rev 108077) @@ -5,7 +5,9 @@ 2.3.1 (unreleased) ------------------
-- Nothing changed yet. +- ``GroupForm`` and ``Group`` now use ``getContent`` method when + instantiating group classes instead of directly accessing + ``self.context``.
2.3.0 (2009-12-28)
Modified: z3c.form/trunk/src/z3c/form/group.py =================================================================== --- z3c.form/trunk/src/z3c/form/group.py 2010-01-12 16:55:11 UTC (rev 108076) +++ z3c.form/trunk/src/z3c/form/group.py 2010-01-12 17:33:51 UTC (rev 108077) @@ -52,7 +52,7 @@ if interfaces.IGroup.providedBy(groupClass): group = groupClass else: - group = groupClass(self.context, self.request, self) + group = groupClass(self.getContent(), self.request, self) group.update() groups.append(group) self.groups = tuple(groups) @@ -130,7 +130,7 @@ if interfaces.IGroup.providedBy(groupClass): group = groupClass else: - group = groupClass(self.context, self.request, self) + group = groupClass(self.getContent(), self.request, self) group.update() groups.append(group) self.groups = tuple(groups)
_______________________________________________ Zope-Dev maillist - Zope-Dev@zope.org https://mail.zope.org/mailman/listinfo/zope-dev ** No cross posts or HTML encoding! ** (Related lists - https://mail.zope.org/mailman/listinfo/zope-announce https://mail.zope.org/mailman/listinfo/zope )
Yours sincerely, -- Michael Howitz · mh@gocept.com · software developer gocept gmbh & co. kg · forsterstraße 29 · 06112 halle (saale) · germany http://gocept.com · tel +49 345 1229889 8 · fax +49 345 1229889 1 Zope and Plone consulting and development
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
Am 19.01.2010 um 16:58 schrieb Laurent Mignon:
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
This might be a solution.
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.
I see it differently. So I'd like to ask what was the original intention of ``getContent``? Anyone here to answer this question?
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) * ...
I might argue the other way round: when you override ``getContent`` in your form resp. group class you are on your own as you changed the default behavior of the form. Then you have to take care for for your groups to get the correct context.
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.
I tried it, it works, both in __init__ and in update. But this also works four your use case.
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
Yours sincerely, -- Michael Howitz · mh@gocept.com · software developer gocept gmbh & co. kg · forsterstraße 29 · 06112 halle (saale) · germany http://gocept.com · tel +49 345 1229889 8 · fax +49 345 1229889 1 Zope and Plone consulting and development
participants (2)
-
Laurent Mignon -
Michael Howitz