@view_config(renderer="templates/form.pt", name="widget_adapter")
@demonstrate("Widget Adapter")
def widget_adapter(self):
# Formish allows you to pair a widget against a type that
# doesn't "natively" lend itself to being representable by the
# widget. For example, it allows you to use a textarea widget
# against a sequence type. To provide this feature, Formish
# uses an adapter to convert the sequence data to text during
# serialization and from text back to a sequence during
# deserialization.
#
# Deform doesn't have such a feature out of the box. This is
# on purpose: the feature is really too complicated and
# magical for civilians. However, if you really want or need
# it, you can add yourself as necessary using an adapter
# pattern.
#
# In the demo method below, we adapt a "normal" textarea
# widget for use against a sequence. The resulting browser UI
# is the same as if we had used a TextAreaCSVWidget against
# the sequence as in the "textareacsv" test method.
#
# N.B.: we haven't automated the lookup of the widget adapter
# based on the type of the field and the type of the widget.
# Instead, we just construct an adapter manually. Adding an
# abstraction to the lookup based on the widget and schema
# types being adapted is easy enough, but trying to follow the
# code path of the abstraction becomes brain bending.
# Therefore, we don't bother to show it.
class Row(colander.TupleSchema):
first = colander.SchemaNode(colander.Integer())
second = colander.SchemaNode(colander.String())
third = colander.SchemaNode(colander.Decimal())
class Rows(colander.SequenceSchema):
row = Row()
class Schema(colander.Schema):
csv = Rows()
schema = Schema()
form = deform.Form(schema, buttons=("submit",))
inner_widget = deform.widget.TextAreaWidget(rows=10, cols=60)
widget = SequenceToTextWidgetAdapter(inner_widget)
form["csv"].widget = widget
appstruct = {"csv": [(1, "hello", 4.5), (2, "goodbye", 5.5)]}
return self.render_form(form, appstruct=appstruct)