WTForms 创建自定义小部件
WTForms的文档实在是太不够用了,他们甚至没有给出一个完全自定义的控件的例子,都是从其他控件派生出来的。
我想做一个按钮类型的控件,但它在HTML中不是一个<input>
标签:
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')
其实我根本不需要一个从Field派生出来的对象。但是当你单独使用Widget的时候,它并不会显示出来。
而当你使用Field对象时,就会出现各种无效参数的错误。
即使深入研究WTForms的源代码,也很难理解为什么它不能把参数从表单传递到控件。
--- 更新 ---
好吧,在我提交问题后,我基本上找到了一个可行的解决方案:
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')
2 个回答
5
你可以利用字段上的一些有用属性,比如'描述'和'标签'。这样可以让设置变得简单很多:
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)))
用法:(为了更好阅读而换行)
class MyForm(Form):
foo = BooleanField(
u'Save',
description='Click here to save',
widget=InlineButtonWidget()
)
另外,你也可以为它设置一个字段类型:
class InlineButtonField(BooleanField):
widget = InlineButtonWidget()
class MyForm(Form):
foo = InlineButtonField('Save', description='Save Me')
5
在更新部分回答了这个问题,但我需要在字段派生类里面进行这个初始化。
def __init__(self, label=None, validators=None, text='Save', **kwargs):
super(InlineButton, self).__init__(label, validators, **kwargs)
self.text = text