我的表单验证工作接近完成,我只有2个案例我不知道如何解决:1)当然应该要求密码字段,但我也提供了使用google或facebook帐户登录的可能性通过OAuth,然后名称被预先填写,但我从表单中完全删除密码字段是有用户(谷歌)或Facebook用户对象:
<tr><td>
<br /> {% if user or current_user %} {% else %}
<div class="labelform">
{% filter capitalize %}{% trans %}password{% endtrans %}{% endfilter %}:
</div>
</td><td> <div class="adinput">{{ form.password|safe }}{% trans %}Choose a password{% endtrans %}</div>{% endif %}
</td></tr>
因此,对于已经登录且密码字段没有意义的用户,我需要一些逻辑来使该字段有条件地可选。我在想我可以为我的表单类中的logged_in +方法创建一个变量,例如:
class AdForm(Form):
logged_in = False
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'))
def validate_password(form, field):
if not logged_in and not field:
raise ValidationError(_('Password is required'))
上述validate_password能否达到预期效果?还有另一种更好的方法吗?我能想到的另一种方法是拥有2个不同的表单类,在http post中我将表单类设置为应该是:
def post(self):
if not current_user:
form = AdForm(self.request.params)
if current_user:
form = AdUserForm(self.request.params)
我还需要对类别字段进行条件验证,当选择某个类别时,会出现更多选项,这些选项应仅针对某个基类进行验证,例如。用户选择“汽车”,然后通过Ajax可以选择汽车的登记数据和里程数,这些字段是必需的,因为选择了汽车类别。
所以这可能是两个问题,但两个案例都涉及我如何使一个字段“有条件可选”或“有条件地要求”。
我的表单看起来像这样
对于已登录的用户,我预先填写姓名和电子邮件地址,并且简单地不使用密码字段,因此密码字段既不适合“可选”也不“必需”,它需要“条件可选”或“有条件地要求。”
感谢您的回答或评论
答案 0 :(得分:63)
我不确定这完全符合您的需求,但我之前在字段上使用了RequiredIf
自定义验证器,如果另一个字段在表单中有值,则需要字段...例如,在日期时区方案中,如果用户输入了日期时间,我可以使时区字段具有值。
class RequiredIf(Required):
# a validator which makes a field required if
# another field is set and has a truthy value
def __init__(self, other_field_name, *args, **kwargs):
self.other_field_name = other_field_name
super(RequiredIf, self).__init__(*args, **kwargs)
def __call__(self, form, field):
other_field = form._fields.get(self.other_field_name)
if other_field is None:
raise Exception('no field named "%s" in form' % self.other_field_name)
if bool(other_field.data):
super(RequiredIf, self).__call__(form, field)
构造函数采用触发此字段的其他字段的名称,如:
class DateTimeForm(Form):
datetime = TextField()
timezone = SelectField(choices=..., validators=[RequiredIf('datetime')])
这可能是实现所需逻辑的良好起点。
答案 1 :(得分:5)
我发现这个问题很有帮助,根据@dcrosta的答案,我创建了另一个可选的验证器。好处是您可以将它与其他wtforms验证器结合使用。这是我的可选验证器,它检查另一个字段。因为我需要根据某个值检查其他字段的值,所以我添加了一个自定义值检查:
class OptionalIfFieldEqualTo(wtf.validators.Optional):
# a validator which makes a field optional if
# another field has a desired value
def __init__(self, other_field_name, value, *args, **kwargs):
self.other_field_name = other_field_name
self.value = value
super(OptionalIfFieldEqualTo, self).__init__(*args, **kwargs)
def __call__(self, form, field):
other_field = form._fields.get(self.other_field_name)
if other_field is None:
raise Exception('no field named "%s" in form' % self.other_field_name)
if other_field.data == self.value:
super(OptionalIfFieldEqualTo, self).__call__(form, field)
答案 2 :(得分:3)
@dcrosta的答案很棒,但我认为自从这个答案以来,wtforms中的一些事情发生了变化。继承自DataRequired
会向表单字段添加required
属性,因此不会调用条件验证程序。我对@dcrosta的类进行了一些小改动,它适用于wtforms 2.1。这只会覆盖field_flags
,以便不进行浏览器验证。
from wtforms.validators import DataRequired
class RequiredIf(DataRequired):
"""Validator which makes a field required if another field is set and has a truthy value.
Sources:
- http://wtforms.simplecodes.com/docs/1.0.1/validators.html
- http://stackoverflow.com/questions/8463209/how-to-make-a-field-conditionally-optional-in-wtforms
"""
field_flags = ('requiredif',)
def __init__(self, other_field_name, message=None, *args, **kwargs):
self.other_field_name = other_field_name
self.message = message
def __call__(self, form, field):
other_field = form[self.other_field_name]
if other_field is None:
raise Exception('no field named "%s" in form' % self.other_field_name)
if bool(other_field.data):
super(RequiredIf, self).__call__(form, field)
更理想的解决方案是设法在浏览器中进行验证,例如DataRequired
的当前行为。