WTForms creates a custom widget

The WTForms documentation is extremely inadequate; they don’t even show you one example of a custom widget that is not already received from another widget.

I am trying to create a button type that is not "entered" in html:

submit = InlineButton (name = 'submit', type = 'submit', title = 'Save this page', textWithinSpan = 'Save')

from flask.ext.wtf import Required, Length, EqualTo, Field, TextInput, html_params from flask import Markup class InlineButtonWidget(object): text = '' html_params = staticmethod(html_params) def __init__(self, input_type='submit', **kwargs): self.input_type = input_type def __call__(self, field, **kwargs): kwargs.setdefault('id', field.id) kwargs.setdefault('type', self.input_type) if 'value' not in kwargs: kwargs['value'] = field._value() return Markup('<button type="submit" %s><span>%s</span></button>' % (self.html_params(name=field.name, **kwargs), kwargs['textWithinSpan'])) class InlineButton(Field): widget = InlineButtonWidget() def __init__(self, label='', **kwargs): self.widget = InlineButtonWidget('submit', label) def __call__(self, **kwargs): return self.widget(self, **kwargs) def _value(self): if self.data: return u', '.join(self.data) else: return u'' class SignupForm(Form): name = TextField('Name', [Length(min=1, max=200)]) submit = InlineButton(name='submit', type='submit', title='Save this page', textWithinSpan='Save') 

I don’t even need a field object. But it does not appear when you use only the widget.

And when you use the Field object, it gives you all kinds of invalid parameter errors.

Even going into the WTForms source code, it’s hard to understand why it will not pass Kwargs from the form to the widget.

--- UPDATE ---

Well, after I asked the question, I basically figured out a workable solution:

 class InlineButtonWidget(object): html_params = staticmethod(html_params) def __init__(self, input_type='submit', text=''): self.input_type = input_type self.text = text def __call__(self, field, **kwargs): kwargs.setdefault('id', field.id) kwargs.setdefault('type', self.input_type) if 'value' not in kwargs: kwargs['value'] = field._value() return Markup('<button type="submit" %s><span>%s</span></button>' % (self.html_params(name=field.name, **kwargs), field.text)) class InlineButton(Field): widget = InlineButtonWidget() def __init__(self, label=None, validators=None, text='Save', **kwargs): super(InlineButton, self).__init__(label, validators, **kwargs) self.text = text def _value(self): if self.data: return u''.join(self.data) else: return u'' class SignupForm(Form): name = TextField('Name', [Length(min=1, max=200)]) submit = InlineButton('submit', text='Save', description='Save this') 
+7
source share
2 answers

Answered in the Upgrade section, but this requires initialization inside the Field derived class.

 def __init__(self, label=None, validators=None, text='Save', **kwargs): super(InlineButton, self).__init__(label, validators, **kwargs) self.text = text 
+3
source

You can use the useful attributes in the field, namely the description and label for this instance. This gives a much simpler setup:

 from wtforms.widgets.core import HTMLString, html_params, escape class InlineButtonWidget(object): def __call__(self, field, **kwargs): kwargs.setdefault('type', 'submit') # Allow passing title= or alternately use field.description title = kwargs.pop('title', field.description or '') params = html_params(title=title, **kwargs) html = '<button %s><span>%s</span></button>' return HTMLString(html % (params, escape(field.label.text))) 

Usage: (wrapped for readability)

 class MyForm(Form): foo = BooleanField( u'Save', description='Click here to save', widget=InlineButtonWidget() ) 

in order to have a field type for it:

 class InlineButtonField(BooleanField): widget = InlineButtonWidget() class MyForm(Form): foo = InlineButtonField('Save', description='Save Me') 
+4
source

All Articles