[Zope3-Users] Transforming formlib field data on save

Marius Gedminas mgedmin at b4net.lt
Tue Jan 22 20:41:06 EST 2008


On Tue, Jan 22, 2008 at 12:28:22PM +1300, andrew wrote:
> I'm struggling with how to transform some input data into an object
> property using an auto-generated formlib edit form, schema, etc. I see
> how the simple flow works, i.e.:
> 
> 1. Create a schema
> 2. Build the form from the schema
> 3. Use applyChanges to update context object properties with input data
> 
> But what if I want to do something other than just set an object
> property ? In this case, I'm working on a content page editor where the
> underlying data is stored as the content of a page template, so I want
> to be able to map a form "content" field to / from the page template
> content instead of a property on the page template.

You can always write a custom action that stores the data wherever you
want.

    class MyPage(form.EditForm):

        form_fields = form.Fields(...)

        actions = form.Actions() # remove the default Apply action

        # and replace it with a custom one:
        @form.action(_("Apply"), condition=form.haveInputWidgets)
        def apply_action(self, action, data):
            self.context.pt_edit(data['content'])
            self.status = _('Saved changes')

You can also combine manual actions with formlib's applyChanges, if you
want to -- just make sure you remove those fields you don't want formlib
to process from the data dict before you call applyChanges.

        @form.action(_("Apply"), condition=form.haveInputWidgets)
        def apply_action(self, action, data):
            self.context.pt_edit(data.pop('content'))
            form.applyChanges(self.context, self.form_fields, data)
            self.status = _('Saved changes')

I'm leaving some details (such as sending IObjectModified events, or not
doing anything if you haven't actually changed any of the values) as an
exercise for the reader.  Read the zope.formlib.form source code for
examples of that.

> Anyone got a simple example of how to go about this ? I'm guessing it's
> something to do with providing an adapter on the content field so I can
> override the get/set methods of the field, but I'm stuck at that point.

If you want to do it via adapters, here you go:

    class ITemplateSource(Interface):
        source = SourceText(title=u"Template source")

    class TemplateSource(object):
        adapts(IMyTemplateInterface)
        provides(ITemplateSource)

        def __init__(self, context):
            self.context = context

        def _getSource(self):
            return self.context.read()

        def _setSource(self, new_source)
            self.context.pt_edit(new_source, 'text/html')

        source = property(_getSource, _setSource)

    # Make sure to provideAdapter(TemplateSource) or the equivalent in
    # ZCML for the following to work:

    class MyPage(form.EditForm):

        form_fields = form.Fields(..., ITemplateSource)

Since ITemplateSource.source is defined in the ITemplateSource
interface, formlib will try to adapt your context to ITemplateSource.

Disclaimer: all code in this email is untested.

HTH,
Marius Gedminas
-- 
An algorithm must be seen to be believed.
                -- D.E. Knuth
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
Url : http://mail.zope.org/pipermail/zope3-users/attachments/20080123/170fb80d/attachment-0001.bin


More information about the Zope3-users mailing list