nested colander schema and validation

211 views
Skip to first unread message

Andi Balke

unread,
Jun 16, 2012, 6:44:39 PM6/16/12
to pylons-discuss
hi, 

i sat on this problem for 10 hours now and i have no idea anymore. if anyone could give me  a hint, i would really appreciate that. 

story: i created a schema for a custom widget, wich renders, the form works, all fine so far. 

problem: i need to create a nested schema so i can access ``children`` in my custom widget to transmit more than only one filed. i had different variations of schemas so far, which all kinda work - e.g. render - but on validation my problem is i cannot access the POST data of the children in my parent-schema.
now i just wanted to see if i can access them at least in a custom validator (http://deformdemo.repoze.org/interfield/), nope. also the preparer just doesn't work on the parent-schema. 

here is all relevant code, maybe someone spots an error. 

thanks, andi

class curry(object):
    """
    class to curry a methods together with fewer arguments.

    """
    def __init__(self, fun, *args, **kwargs):
        self.fun = fun
        self.pending = args[:]
        self.kwargs = kwargs.copy()

    def __call__(self, *args, **kwargs):
        if kwargs and self.kwargs:
            kw = self.kwargs.copy()
            kw.update(kwargs)
        else:
            kw = kwargs or self.kwargs

        return self.fun(*(self.pending + args), **kw)


@colander.deferred
def create_LocationPickerWidget(node, kw):
    """
    callable to create the widget with a deferred paramater, here
    "request"

    gets applied by ``colander.Schema.bind(request=self.request)``
    """
    request = kw["request"]
    return LocationPickerWidget(request)

class Location(colander.MappingSchema):
    location_search = colander.SchemaNode(
        colander.String(),
        name = "location_string.location_search",
        validator=colander.Length(min=1),
    )
    location_point = colander.SchemaNode(
        colander.String(),
        name = "location_string.location_point",
        widget = deform.widget.HiddenWidget(),
        validator=colander.Length(min=1),
    )


class LocationPicker(colander.MappingSchema):
    """
    schema only for a step in the form to choose a location

    """
    location_string = Location(
        widget=create_LocationPickerWidget,
    )

    @classmethod
    def prepare_location(cls, fieldname, value):
        """
        deform preparer to convert a form submitted location in a real
        location.

        appended below
        """
        if log.isEnabledFor(logging.WARN):
            _out = StringIO()
            pprint(value, stream=_out)
            log.warn("%s.%s @%s value: %s", __name__, cls.__name__, fieldname, _out.getvalue())

        if value:
            lat, lng = value.split(',')
            position = WKTSpatialElement('POINT({0} {1})'.format(lat, lng))
            return position
        return value

# adding a preparer to the mapping node will not work
LocationPicker.location_string.preparer =\
        curry(LocationPicker.prepare_location, "XX_location_string_XX")
# those work
Location.location_search.preparer =\
        curry(LocationPicker.prepare_location, "location_search")
Location.location_point.preparer =\
        curry(LocationPicker.prepare_location, "location_point")

Andi Balke

unread,
Jun 18, 2012, 10:15:07 AM6/18/12
to pylons-discuss
hi, 

the solution to get the nested fields applied correctly lies in the template::

    <input type="hidden" name="__start__" value="${field.name}:mapping"/>
    <div tal:repeat="tup subfields">
        <div tal:replace="structure rndr(tup[1].widget.template, field=tup[1], cstruct=tup[0],
                      parent=field)"/>
    </div>

    <input type="text"
           name="${item_field.name}"
           value="${cstruct['location_search']}"
           tal:attributes="size field.widget.size;
                           class field.widget.css_class"
           id="${item_field.oid}" />
    <input type="hidden" name="__end__" value="${field.name}:mapping"/>

cheers, andi
Reply all
Reply to author
Forward
0 new messages