【问题标题】:How to render DateField with 3 selects如何使用 3 次选择呈现 DateField
【发布时间】:2013-02-01 09:29:08
【问题描述】:

我正在寻找使用 3 选择呈现基本 DateField 的最简单、最干净的方法。

<select>day</select><select>month</select><select>year</select>

(如果可能,使用“格式”来选择如何显示最终渲染)

【问题讨论】:

    标签: python flask wtforms flask-wtforms


    【解决方案1】:

    您可以利用 DateField 将处理多值输入并将它们用空格连接在一起的事实,因此您可以避免使用辅助形式,而只需提供输入序列:

    from wtforms.widgets.core import Select, HTMLString, html_params
    
    class SelectDateWidget(object):
        FORMAT_CHOICES = {
            '%d': [(x, str(x)) for x in range(1, 32)],
            '%m': [(x, str(x)) for x in range(1, 13)],
            '%y': [(x, str(x)) for x in range(1950, 2014)],
        }
    
        def __call__(self, field, **kwargs):
            field_id = kwargs.pop('id', field.id)
            html = []
            for format in field.format.split():
                choices = self.FORMAT_CHOICES[format]
                id_suffix = format.replace('%', '-')
                params = dict(kwargs, name=field.name, id=field_id + id_suffix)
                html.append('<select %s>' % html_params(params))
                if field.data:
                    current_value = int(field.data.strftime(format))
                else:
                    current_value = None
                for value, label in choices:
                    selected = (value == current_value)
                    html.append(Select.render_option(value, label, selected))
                html.append('</select>')
    
            return HTMLString(''.join(html))
    
    
    # Usage
    class MyForm(Form):
        american_date = DateField(format='%m %d %y', widget=SelectDateWidget())
        european_date = DateField(format='%d %m %y', widget=SelectDateWidget())
    

    【讨论】:

    • 非常优雅的解决方案 :) 谢谢。
    【解决方案2】:

    最终小部件:(不仅支持空格,还支持多种格式)

    class SelectDateWidget(object):
      FORMAT_CHOICES = {
        '%d': [(x, str(x)) for x in range(1, 32)],
        '%m': [(x, str(x)) for x in range(1, 13)]
      }
    
      FORMAT_CLASSES = {
        '%d': 'select_date_day',
        '%m': 'select_date_month',
        '%Y': 'select_date_year'
      }
    
      def __init__(self, years=range(1930, 2014)):
        super(SelectDateWidget, self).__init__()
        self.FORMAT_CHOICES['%Y'] = [(x, str(x)) for x in years]
    
      def __call__(self, field, **kwargs):
        field_id        = kwargs.pop('id', field.id)
        html            = []
        allowed_format  = ['%d', '%m', '%Y']
    
        for format in field.format.split():
          if (format in allowed_format):
            choices     = self.FORMAT_CHOICES[format]
            id_suffix   = format.replace('%', '-')
            id_current  = field_id + id_suffix
    
            kwargs['class'] = self.FORMAT_CLASSES[format]
            try: del kwargs['placeholder']
            except: pass
    
            html.append('<select %s>' % html_params(name=field.name, id=id_current, **kwargs))
    
            if field.data:
                current_value = int(field.data.strftime(format))
            else:
                current_value = None
    
            for value, label in choices:
              selected = (value == current_value)
              html.append(Select.render_option(value, label, selected))
            html.append('</select>')
          else:
            html.append(format)
            html.append('<input type="hidden" value="'+format+'" %s></input>' % html_params(name=field.name, id=id_current, **kwargs))
    
          html.append(' ')
    
        return HTMLString(''.join(html))
    

    【讨论】:

    • 如何访问模板中的各个日、月、年子字段?提前致谢。
    【解决方案3】:

    我使用了一个自定义小部件,它可以工作,但还不完美。其他想法?

    class SelectDateWidget(object):
        class SelectDateForm(Form):
          days   = [(x,x) for x in range(1,32)]
          months = [(x,x) for x in range(1,13)]
          years  = [(x,x) for x in range(1950,2014)]
    
          days_select  = SelectField(choices=days)
          month_select = SelectField(choices=months)
          year_select  = SelectField(choices=years)
    
        def __call__(self, field, **kwargs):
          kwargs.setdefault('id', field.id)
    
          date_form   = self.SelectDateForm(prefix=field.name)
    
          days_html  = date_form.days_select(class_="input-mini").__html__()
          month_html = date_form.month_select(class_="input-mini").__html__()
          year_html  = date_form.year_select(class_="input-small").__html__()
    
          widget_html = field.format
          widget_html = widget_html.replace('%d', days_html) 
          widget_html = widget_html.replace('%m', month_html) 
          widget_html = widget_html.replace('%Y', year_html) 
    
          return HTMLString(widget_html)
    
    class SelectDateField(DateField):
      widget = SelectDateWidget()
      def __init__(self, label=None, validators=None, **kwargs):
        super(SelectDateField, self).__init__(label, validators, **kwargs)
    
      def pre_validate(self, extra):
        form   = SelectDateWidget.SelectDateForm(prefix=self.name)
    
        try:    
          date      = datetime.datetime.strptime(form.days_select.data+'-'+form.month_select.data+'-'+form.year_select.data, '%d-%m-%Y')
          self.data = date
        except: 
          raise StopValidation(gettext(u'Invalid date.'))
    
    class MyForm(Form):
      date = SelectDateField(u'Date', validators=[Required(message=_(u'This field is required.'))], format='%d / %m / %Y') 
    

    【讨论】:

    • 我自己还没试过,但是你有没有查看过 wtforms 中的 SelectMultipleField() 字段?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-23
    • 2015-02-02
    • 1970-01-01
    相关资源
    最近更新 更多