У меня есть поле выбора, в котором некоторые элементы исчезли и отключены, которые я хотел бы визуализировать с помощью 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 & Parts{% endtrans %}</option>
...
У меня есть класс формы, который работает, и я начал внедрять в локализованную переменную категории, но я не знаю, как сделать виджет (?), Который отображает блеклые (background-color:#dcdcc3
) и отключенные атрибуты в элементе option :
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'))
Я могу использовать переменную категорию сверху, чтобы сделать выбор для категорий. Я также хочу включить специальный рендеринг, т.е. отключенные элементы и блеклый фон. Можете ли вы сказать мне, как я должен делать?
Спасибо
Обновление
При попытке решения из ответа добавить атрибут disabled, я получаю следующее сообщение об ошибке:
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', но где?
Обновление 2
Это было сложнее, чем я думал. Было также предложено решение, предложенное в списке рассылки wtforms , но я также не смог заставить его работать (какая-то тривиальная ошибка, связанная с неверным синтаксисом и невозможностью импортировать ecscape из wtforms, поэтому выполняемое мною действие обновлялось мой wtforms из репозитория hg, если там что-то изменилось.
Из ответа здесь я получаю Need more than 2 values to unpack
или ValueError: too many values to unpack
, поэтому я не могу понять, что это правильно. В моем шаблоне то, что я пытаюсь сделать, это
{{ form.category }}
и у меня класс формы
class AdForm(Form):
my_choices = [('1', _('VEHICLES'), False, True), ('2', _('Cars'), False, False), ('3', _('Motorcycles'), False, False)]
...
category = SelectFieldWithDisable(choices = my_choices)
с добавленными классами, которые я получил отсюда:
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)