如何使用WTForms呈现我的选择字段? [英] How to render my select field with WTForms?

查看:96
本文介绍了如何使用WTForms呈现我的选择字段?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个select字段,其中某些元素已淡化和禁用,我想使用WTForms进行渲染:

I have a select field that has certain elements faded and disabled that I would like to render with WTForms:

<select name="cg" id="cat" class="search_category">
<option value='' >{% trans %}All{% endtrans %}</option>  
<option value='' style='background-color:#dcdcc3' id='cat1'  disabled="disabled">-- {% trans %}VEHICLES{% endtrans %} --</option>
<option value='2'  {% if "2" == cg %} selected="selected" {% endif %} id='cat2' >{% trans %}Cars{% endtrans %}</option>
<option value='3' {% if "3" == cg %} selected="selected" {% endif %}   id='cat3' >{% trans %}Motorcycles{% endtrans %}</option>
<option value='4' {% if "4" == cg %} selected="selected" {% endif %}   id='cat4' >{% trans %}Accessories &amp; Parts{% endtrans %}</option>
...

我有一个有效的表单类,并且我开始实现本地化的类别变量,但是我不知道如何制作将褪色的(background-color:#dcdcc3)和禁用的属性呈现给option元素的widget(?) :

I have a form class that works and I started to implement to localized category variable but I don't know how to make the widget(?) that renders the faded (background-color:#dcdcc3) and the disabled attributes to an option element:

class AdForm(Form):
    my_choices = [('1', _('VEHICLES')), ('2', _('Cars')), ('3', _('Bicycles'))]
    name = TextField(_('Name'), [validators.Required(message=_('Name is required'))], widget=MyTextInput())
    title = TextField(_('title'), [validators.Required(message=_('Subject is required'))], widget=MyTextInput())
    text = TextAreaField(_('Text'),[validators.Required(message=_('Text is required'))], widget=MyTextArea())
    phonenumber = TextField(_('Phone number'))
    phoneview = BooleanField(_('Display phone number on site'))
    price = TextField(_('Price'),[validators.Regexp('\d', message=_('This is not an integer number, please see the example and try again')),validators.Optional()] )
    password = PasswordField(_('Password'),[validators.Optional()], widget=PasswordInput())
    email = TextField(_('Email'), [validators.Required(message=_('Email is required')), validators.Email(message=_('Your email is invalid'))], widget=MyTextInput())
    category = SelectField(choices = my_choices, default = '1')

    def validate_name(form, field):
        if len(field.data) > 50:
            raise ValidationError(_('Name must be less than 50 characters'))

    def validate_email(form, field):
        if len(field.data) > 60:
            raise ValidationError(_('Email must be less than 60 characters'))

    def validate_price(form, field):
        if len(field.data) > 8:
            raise ValidationError(_('Price must be less than 9 integers'))

我可以使用上面的变量类别来呈现类别的选择.我也想启用特殊渲染,即禁用的元素和褪色的背景.你能告诉我我应该怎么做吗?

I can use the variable category from above to render a select for the categories. I also want to enable the special rendering ie disabled elements and faded background. Can you tell me how I should do?

谢谢

尝试从答案中添加添加禁用属性的解决方案时,出现以下错误消息:

When trying the solution from the answer to add the disabled attribute, I get this error message:

Trace:

Traceback (most recent call last):
  File "/media/Lexar/montao/lib/webapp2/webapp2.py", line 545, in dispatch
    return method(*args, **kwargs)
  File "/media/Lexar/montao/montaoproject/i18n.py", line 438, in get
    current_user=self.current_user,
  File "/media/Lexar/montao/montaoproject/main.py", line 469, in render_jinja
    self.response.out.write(template.render(data))
  File "/media/Lexar/montao/montaoproject/jinja2/environment.py", line 894, in render
    return self.environment.handle_exception(exc_info, True)
  File "/media/Lexar/montao/montaoproject/templates/insert_jinja.html", line 221, in top-level template code
    {{ form.category|safe }}
ValueError: need more than 2 values to unpack

我尝试的代码是:

from wtforms.widgets import html_params
class SelectWithDisable(object):
    """
    Renders a select field.

    If `multiple` is True, then the `size` property should be specified on
    rendering to make the field useful.

    The field must provide an `iter_choices()` method which the widget will
    call on rendering; this method must yield tuples of 
    `(value, label, selected, disabled)`.
    """
    def __init__(self, multiple=False):
        self.multiple = multiple

    def __call__(self, field, **kwargs):
        kwargs.setdefault('id', field.id)
        if self.multiple:
            kwargs['multiple'] = 'multiple'
        html = [u'<select %s>' % html_params(name=field.name, **kwargs)]
        for val, label, selected, disabled in field.iter_choices():
            html.append(self.render_option(val, label, selected, disabled))
        html.append(u'</select>')
        return HTMLString(u''.join(html))

    @classmethod
    def render_option(cls, value, label, selected, disabled):
        options = {'value': value}
        if selected:
            options['selected'] = u'selected'
        if disabled:
            options['disabled'] = u'disabled'
        return HTMLString(u'<option %s>%s</option>' % (html_params(**options), escape(unicode(label))))


class SelectFieldWithDisable(SelectField):
    widget = SelectWithDisable()

    def iter_choices(self):
        for value, label, selected, disabled in self.choices:
            yield (value, label, selected, disabled, self.coerce(value) == self.data)


class AdForm(Form):
    my_choices = [('1', _('VEHICLES')), ('2', _('Cars')), ('3', _('Motorcycles'))]
    nouser = HiddenField(_('No user'))
    name = TextField(_('Name'), [validators.Required(message=_('Name is required'))], widget=MyTextInput())
    title = TextField(_('Subject'), [validators.Required(message=_('Subject is required'))], widget=MyTextInput())
    text = TextAreaField(_('Text'),[validators.Required(message=_('Text is required'))], widget=MyTextArea())
    phonenumber = TextField(_('Phone number'))
    phoneview = BooleanField(_('Display phone number on site'))
    price = TextField(_('Price'),[validators.Regexp('\d', message=_('This is not an integer number, please see the example and try again')),validators.Optional()] )
    password = PasswordField(_('Password'),validators=[RequiredIf('nouser', message=_('Password is required'))], widget=MyPasswordInput())
    email = TextField(_('Email'), [validators.Required(message=_('Email is required')), validators.Email(message=_('Your email is invalid'))], widget=MyTextInput())
    category = SelectFieldWithDisable(choices = my_choices)

    def validate_name(form, field):
        if len(field.data) > 50:
            raise ValidationError(_('Name must be less than 50 characters'))

    def validate_email(form, field):
        if len(field.data) > 60:
            raise ValidationError(_('Email must be less than 60 characters'))

    def validate_price(form, field):
        if len(field.data) > 8:
            raise ValidationError(_('Price must be less than 9 integers'))

我想我必须在某个地方但在哪里设置"disabled"属性?

I guess I must set the 'disabled' attribute somewhere but where?

这比我想的要难. wtforms邮件列表上还建议了一个解决方案,但我也无法使它正常工作(有关无效语法和无法从wtforms导入ecscape的一些琐碎错误,因此,如果在那里发生了重要变化,我采取的措施是从hg存储库中更新我的wtforms.

This was trickier than I thought. There was also a solution suggested on the wtforms mailing list but I couldn't get that to work either (some trivial error about invalid syntax and not being able to import ecscape from wtforms so the action I took was updating my wtforms from the hg repository if something important changed there.

从这里的答案中我得到Need more than 2 values to unpackValueError: too many values to unpack,所以我似乎无法正确地做到这一点.在我的模板中,我要呈现的是

From the answer here I either get Need more than 2 values to unpack or ValueError: too many values to unpack so I canät seem to get it right. In my template what I'm trying to render is

{{ form.category }} 

我的表单类是

class AdForm(Form):
    my_choices = [('1', _('VEHICLES'), False, True), ('2', _('Cars'), False, False), ('3', _('Motorcycles'), False, False)]

    ...
    category = SelectFieldWithDisable(choices = my_choices)

我从这里得到的添加的类:

with the added classes I got from here:

class SelectWithDisable(object):
    """
    Renders a select field.

    If `multiple` is True, then the `size` property should be specified on
    rendering to make the field useful.

    The field must provide an `iter_choices()` method which the widget will
    call on rendering; this method must yield tuples of 
    `(value, label, selected, disabled)`.
    """
    def __init__(self, multiple=False):
        self.multiple = multiple

    def __call__(self, field, **kwargs):
        kwargs.setdefault('id', field.id)
        if self.multiple:
            kwargs['multiple'] = 'multiple'
        html = [u'<select %s>' % html_params(name=field.name, **kwargs)]
        for val, label, selected, disabled in field.iter_choices():
            html.append(self.render_option(val, label, selected, disabled))
        html.append(u'</select>')
        return HTMLString(u''.join(html))

    @classmethod
    def render_option(cls, value, label, selected, disabled):
        options = {'value': value}
        if selected:
            options['selected'] = u'selected'
        if disabled:
            options['disabled'] = u'disabled'
        return HTMLString(u'<option %s>%s</option>' % (html_params(**options), escape(unicode(label))))


class SelectFieldWithDisable(SelectField):
    widget = SelectWithDisable()

    def iter_choices(self):
        for value, label, selected, disabled in self.choices:
            yield (value, label, selected, disabled, self.coerce(value) == self.data)

推荐答案

如果要始终在禁用某些选项的情况下渲染字段,则必须创建自己的自定义窗口小部件和字段以提供给渲染器.

If you want to always render the field with certain options disabled you'll have to create your own custom widget and field to provide to the renderer.

当前渲染器的选择元组中只有三个选项:(value, name, selected).

The current renderer only takes three options in it's choice tuple: (value, name, selected).

您需要对其进行修改以接受第四个可选元素:禁用.

You'll need to modify that to accept a fourth optional element: disabled.

基于wtforms.widget中的Select类:

Based on the Select class in wtforms.widget:

class SelectWithDisable(object):
    """
    Renders a select field.

    If `multiple` is True, then the `size` property should be specified on
    rendering to make the field useful.

    The field must provide an `iter_choices()` method which the widget will
    call on rendering; this method must yield tuples of 
    `(value, label, selected, disabled)`.
    """
    def __init__(self, multiple=False):
        self.multiple = multiple

    def __call__(self, field, **kwargs):
        kwargs.setdefault('id', field.id)
        if self.multiple:
            kwargs['multiple'] = 'multiple'
        html = [u'<select %s>' % html_params(name=field.name, **kwargs)]
        for val, label, selected, disabled in field.iter_choices():
            html.append(self.render_option(val, label, selected, disabled))
        html.append(u'</select>')
        return HTMLString(u''.join(html))

    @classmethod
    def render_option(cls, value, label, selected, disabled):
        options = {'value': value}
        if selected:
            options['selected'] = u'selected'
        if disabled:
            options['disabled'] = u'disabled'
        return HTMLString(u'<option %s>%s</option>' % (html_params(**options), escape(unicode(label))))

然后根据wtforms.fields中的代码,将已经存在的SelectField子类化

And then based on the code in wtforms.fields, subclass the SelectField that already exists

class SelectFieldWithDisable(SelectFiel):
    widget = widgets.SelectWithDisable()

    def iter_choices(self):
        for value, label, selected, disabled in self.choices:
            yield (value, label, selected, disabled, self.coerce(value) == self.data)

注意:既不进行测试,也没有运行python代码,但是给定了问题和来自WTforms的基本代码,这是一个非常快速的过程.但这应该为您提供足够的开端和先前的答案,以完全控制该领域.

NOTE: THIS IS NOT TESTED NOR EVEN RUN PYTHON CODE BUT A VERY QUICK HACK GIVEN THE QUESTION AND THE UNDERLYING CODE FROM WTFORMS. But it should give you enough of a head start along with the previous answer to control the field entirely.

使用CSS和JavaScript控制页面上的呈现元素.

Use CSS and JavaScript to control the rendered element on the page.

在您使用的任何模板渲染系统中(我正在使用flask,jinja和wtforms),您都可以渲染元素,并在渲染时提供id或class属性. (我只是打印form.select_field_variable_name)

In whatever template rendering system your using (I'm using flask, jinja and wtforms) you render your elemen and provide an id or class attribute when you render it. (I'm just printing form.select_field_variable_name)

然后生成一个CSS文件来控制您的样式,并使用JavaScript来控制对某些元素等的自定义禁用.

Then generate a CSS file to control your styling and use JavaScript to control custom disabling of certain elements, etc.

如果您有:

<select id=selector>
    <option id=value1 value=1>Bananas</option>
    <option id=value2 value=2>Corn</option>
    <option id=value3 value=3>Lolcats</option>
</select>

您可以通过以下方法应用背景色:

You can apply a background color with:

<style>
#selector {background-color: #beef99}
</style>

您可以通过以下方式启用/禁用:

And you enable/disable with:

<script>
option = document.getElementById('value3')
option.disabled = true
</script>

等等,等等.

一旦您使用WTForms小部件渲染了元素,就像所有HTML元素一样,您应该使用CSS和JavaScript设置样式并控制元素的任何动态部分

Once you've got your element rendered using WTForms widgets, like all HTML elements, you should style and control any dynamic parts of the element with CSS and JavaScript

这篇关于如何使用WTForms呈现我的选择字段?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆