WTForms creating a custom widget

我与影子孤独终老i 提交于 2019-12-19 05:58:23

问题


The WTForms documentation is woefully inadequate, they don't even show you one single example of a custom widget that isn't derived from another widget already.

I am trying to make a button type, that isn't an <input> in html:

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

This is what I'm trying:

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 shouldn't even need a Field derived object. But it doesn't display when you only use Widget by itself.

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

Even delving into the WTForms source code makes it difficult to understand why it won't pass Kwargs from form to widget.

--- UPDATE ---

Ok, after I submit 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')

回答1:


Answered under Update, but needed this init inside Field derived class.

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



回答2:


You can take advantage of useful attributes on the field, namely 'description' and 'label' for this instance. This yields 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()
    )

alternately, to have a field type for it:

class InlineButtonField(BooleanField):
    widget = InlineButtonWidget()

class MyForm(Form):
    foo = InlineButtonField('Save', description='Save Me')


来源:https://stackoverflow.com/questions/14510630/wtforms-creating-a-custom-widget

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!