title: How to render my select field with WTForms?
body: <p>I have a select field that has certain elements faded and disabled that I would like to render with WTForms:</p>
  
  <pre><code>&lt;select name="cg" id="cat" class="search_category"&gt;
  &lt;option value='' &gt;{% trans %}All{% endtrans %}&lt;/option&gt;  
  &lt;option value='' style='background-color:#dcdcc3' id='cat1'  disabled="disabled"&gt;-- {% trans %}VEHICLES{% endtrans %} --&lt;/option&gt;
  &lt;option value='2'  {% if "2" == cg %} selected="selected" {% endif %} id='cat2' &gt;{% trans %}Cars{% endtrans %}&lt;/option&gt;
  &lt;option value='3' {% if "3" == cg %} selected="selected" {% endif %}   id='cat3' &gt;{% trans %}Motorcycles{% endtrans %}&lt;/option&gt;
  &lt;option value='4' {% if "4" == cg %} selected="selected" {% endif %}   id='cat4' &gt;{% trans %}Accessories &amp;amp; Parts{% endtrans %}&lt;/option&gt;
  ...
  </code></pre>
  
  <p>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 (<code>background-color:#dcdcc3</code>) and the disabled attributes to an option element:</p>
  
  <pre><code>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) &gt; 50:
              raise ValidationError(_('Name must be less than 50 characters'))
  
      def validate_email(form, field):
          if len(field.data) &gt; 60:
              raise ValidationError(_('Email must be less than 60 characters'))
  
      def validate_price(form, field):
          if len(field.data) &gt; 8:
              raise ValidationError(_('Price must be less than 9 integers'))
  </code></pre>
  
  <p>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?</p>
  
  <p>Thank you</p>
  
  <h2>Update</h2>
  
  <p>When trying the solution from the answer to add the disabled attribute, I get this error message:</p>
  
  <pre><code>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
  </code></pre>
  
  <p>The code I tried was:</p>
  
  <pre><code>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'&lt;select %s&gt;' % 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'&lt;/select&gt;')
          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'&lt;option %s&gt;%s&lt;/option&gt;' % (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) &gt; 50:
              raise ValidationError(_('Name must be less than 50 characters'))
  
      def validate_email(form, field):
          if len(field.data) &gt; 60:
              raise ValidationError(_('Email must be less than 60 characters'))
  
      def validate_price(form, field):
          if len(field.data) &gt; 8:
              raise ValidationError(_('Price must be less than 9 integers'))
  </code></pre>
  
  <p>I guess I must set the 'disabled' attribute somewhere but where?</p>
  
  <h2>Update 2</h2>
  
  <p>This was trickier than I thought. There was also a <a href="https://groups.google.com/forum/#!topic/wtforms/aR-T70qt4wA" rel="noreferrer">solution suggested on the wtforms mailing list</a> 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. </p>
  
  <p>From the answer here I either get <code>Need more than 2 values to unpack</code> or <code>ValueError: too many values to unpack</code> so I canät seem to get it right. In my template what I'm trying to render is</p>
  
  <pre><code>{{ form.category }} 
  </code></pre>
  
  <p>and my form class is</p>
  
  <pre><code>class AdForm(Form):
      my_choices = [('1', _('VEHICLES'), False, True), ('2', _('Cars'), False, False), ('3', _('Motorcycles'), False, False)]
  
      ...
      category = SelectFieldWithDisable(choices = my_choices)
  </code></pre>
  
  <p>with the added classes I got from here:</p>
  
  <pre><code>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'&lt;select %s&gt;' % 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'&lt;/select&gt;')
          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'&lt;option %s&gt;%s&lt;/option&gt;' % (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)
  </code></pre>