将多个字段作为一个进行验证?

4 投票
1 回答
2466 浏览
提问于 2025-04-17 12:33

我的输入格式有点奇怪,但按照规范来讲是这样的:

这里输入图片描述

用户需要在4个字段中输入一个ID,这个ID的格式是460 000 005 001,其中46是国家代码,后面的部分是用户的appengine ID。现在我想给这个字段添加验证,但我在使用wtforms时遇到了问题。以下是我的表单类:

class RegisterWTForm(Form):
    soc_sec = TextField(_('Soc security number'),  [validators.Regexp('^[0-9]+$',
                      message=_('This is not a social security number, please see the example and try again'
                      )), validators.Required(message=_('Social security number is required')), unique_soc_sec], widget=MyTextInput())
    email = TextField(_('Email'),
                      [validators.Required(message=_('Email is required'
                      )),
                      validators.Email(message=_('Your email is invalid'
                      ))], widget=MyTextInput())

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

现在我使用这些变量的方式是,它们并不是WTForm的一部分,而是普通的http post参数:

def post(self):
    Log1 = self.request.POST.get('Log1')
    Log2 = self.request.POST.get('Log2')
    Log3 = self.request.POST.get('Log3')
    Log4 = self.request.POST.get('Log4')    
    form = RegisterWTForm(self.request.params)
    if form.validate():
        logging.info('validated successfully')
    else:
        logging.info('form did not validate')
        self.render_jinja('register.html', form=form, Log1=Log1, Log2=Log2, Log3=Log3, Log4=Log4 )
        return ''
    email = self.request.POST.get('email')

    sponsor_id = '%s%s%s' % (Log2, Log3, Log4)
    if sponsor_id:
        user = User.get_by_id(long(sponsor_id))
    else:
        return 'Sponsor with sponsor id %s does not exist' % sponsor_id
    if not user:
            return 'Sponsor with sponsor id %s does not exist' % sponsor_id

    # make a token for a one-time login link that sets the password
    # Passing password_raw=password so password will be hashed
    # Returns a tuple, where first value is BOOL. If True ok, If False no new user is created

    user = self.auth.store.user_model.create_user(email)

有没有办法把我的4个变量作为一个变量添加到WTForm中,并在里面进行验证?还是说我应该为这些字段自己写一个自定义的验证?对于我的其他字段,如果验证不通过,我会用红色边框和红色文字来标记,我也想在这里做到这一点,但如果不能在表单类中处理,就得把逻辑放到模板里,这样会让展示层的逻辑变得复杂。你能给我一些建议吗?

谢谢

更新

我可以创建一个FormField来组合这些字段,但它们的显示效果不太对,而且我并不需要所有4个字段的验证。也许你能告诉我更多如何按照我想要的方式来做?

class SponsorWTForm(Form):
    log1 = IntegerField('log1', [validators.required()])
    log2 = IntegerField('log2', [validators.required()])
    log3 = IntegerField('log3', [validators.required()])
    log4 = IntegerField('log4', [validators.required()])

class RegisterWTForm(Form):
    sponsor_id = FormField(SponsorWTForm)

...

这里输入图片描述

1 个回答

5

看起来WTForms是通过字段封装来解决这个问题的。链接中的例子是关于一个电话号码的,它把区号和号码分开,这跟你提到的多部分身份证号的情况很相似。

要正确显示这个子表单,你需要定义一个自定义的小部件。可以看看ListWidget的源代码。你的这个小部件可能会类似,但会更简单(因为我觉得你只需要在不同的字段之间留个空格,而不是HTML标签)。像这样简单的代码

return HTMLString(u' '.join([subfield() for subfield in field]))

可能就能满足你的需求。然后在FormField构造函数的参数中加上widget=SingleLineWidget()(或者你给你的小部件类起的其他名字)。

稍微偏题一点,在Django表单中实现这个功能的方法就很不一样了:你需要定义自定义的清理和验证方法,这些方法会处理你的数据(比如在这个例子中,把4个身份证字段合并成一个)。

撰写回答