【问题标题】:Using flask wtforms validators without using a form在不使用表单的情况下使用烧瓶 wtforms 验证器
【发布时间】:2015-08-18 01:17:25
【问题描述】:

我从 iOS 应用程序接收用户注册数据,我想使用 wtforms 附带的验证器来确保电子邮件和密码是可接受的。但是,我没有使用烧瓶表单,因为用户正在从 iOS 文本字段中输入数据。是否可以使用 wtforms 验证器检查传入的 JSON 数据?

@auth.route('/register', methods=['POST'])
def register():
    try:
        user = User.register_fromJSON(request.json)

        email_success = validate_email(user)
        username_success = validate_username(user)

        if email_success == 1 and username_success == 1:
            db.session.add(user)
            db.session.commit()
            return jsonify({'Success': 1})
        else:
            return jsonify({'Failure': 0})

    except Exception:
        return jsonify({'Failure': 0})

def validate_email(user):
    if User.query.filter_by(email=user.email).first() == None:
        return 1
    else:
        return 0

def validate_username(user):
    if User.query.filter_by(username=user.username).first() == None:
        return 1
    else:
        return 0

编辑

我创建了一个注册表单:

class RegistrationForm(Form):
    email = StringField('Email', validators=[Required(), Length(1,64), Email()])
    username = StringField('Username', validators=[Required(), Length(1, 64), Regexp('^[A-Za-z][A-Za-z0-9_.]*$', 0, 'Usernames must have only letters, 'numbers, dots or underscores')])
    password = PasswordField('Password', validators=[Required()])


    def validate_email(self, field):
        if User.query.filter_by(email=field.data).first():
            print("Email already registered.")
            raise ValidationError('Email already registered.')

    def validate_username(self, field):
        if User.query.filter_by(username=field.data).first():
            print("Username already in use.")
            raise ValidationError('Username already in use.')

注册功能已更新为:

@auth.route('/register', methods=['POST'])
def register():
    try:
        data = MultiDict(mapping=request.json)
        form = RegistrationForm(data)

        if form.validate():
            user = User.register_fromJSON(request.json)
            db.session.add(user)
            db.session.commit()
            return jsonify({'Success': 1})
        else:
            return jsonify({'Success': 2})

    except Exception:
        return jsonify({'Success': 3})

【问题讨论】:

  • 当然。我实际上正在编写一个完全可以做到这一点的库。在我的手机上,但当我回到键盘上时我会发布答案

标签: python flask


【解决方案1】:

是的,这是完全可能的 - wtforms.Form 构造函数采用任何类似 MultiDict 的接口 (it just needs to have getlist),因此您可以从 JSON 中创建 werkzeug.datastructures.MultiDict 的实例:

data = MultiDict(mapping=request.json)
form = YourForm(data)
if form.validate():
    # Data is correct

(假设字段名称匹配)并且事情会正常工作

【讨论】:

  • 那么您实际上是在制作一个虚假的表单,将 JSON 数据分配给然后进行验证?
  • 是的,有效。我正在使用 Flask / Werkzeug 用于request.form 的底层数据结构,从request.json 的解析字典中构建一个类似字典的对象 - 所以 WTForms 会处理它。 WTForms 不关心数据是从 HTML 表单 POST 还是从 INI 文件中解析出来的——它只需要以类似于MultiDict 的数据结构提供。
  • 我似乎无法验证表单。我错过了什么吗?我可以通过执行 form.email.data 打印表单数据,一切都正确。
  • 如果您使用的是 Flask-WTF,请确保您已禁用 CSRF 保护,否则表单将永远无法验证 :-)
  • 就是这样!谢谢!我仍然对 MultiDict 行发生的事情感到有些困惑。为什么我不能使用普通字典?我对 python/flask 有点陌生,我对整个映射的东西不太熟悉。
【解决方案2】:

这是一个名为Flask-Inputs 的小实用程序,我正在努力解决这个问题。目标是允许使用 wtform 验证器验证所有传入数据(表单、查询、标题等)。

验证将如何处理您的数据:

from flask_inputs import Inputs
from wtforms.validators import Length, Email, ValidationError


class RegisterInputs(Inputs):
    json = {
        'email': [Email(), unique_email],
        'username': [Length(min=3, max=15), unique_username]
    }

def unique_email(form, field):
    if User.query.filter_by(email=field.data).first():
        raise ValidationError('Email is already registered.')

def unique_username(form, field):
    if User.query.filter_by(username=field.data).first():
        raise ValidationError('Username is already registered.')


@auth.route('/register', methods=['POST'])
def register():
    inputs = RegisterInputs(request)

    if inputs.validate():
        user = User.register_fromJSON(request.json)

        db.session.add(user)
        db.session.commit()

        return jsonify(success=1)
    else:
        return jsonify(failure=0, errors=inputs.errors)

【讨论】:

  • 所以在register() 下,请求作为参数发送到RegisterInputs()。现在,inputs 只是一个包含电子邮件和用户名的键和值的字典吗?因为一切都发生在user = User.register_fromJSON(request.json)之前,这一切难道不是在数据从JSON转换之前发生的吗?
  • inputs 就像 wtforms 中的一个表单实例。您可以调用 inputs.validate() 来检查 json 是否有效
  • 对不起,如果我吹毛求疵,但我认为需要先解析 JSON 数据,然后将其输入到表单实例中。我的逻辑错了吗?您的答案看起来像是用直接的 JSON 数据填充表单实例。
  • 不,request.json 已经是一个解析的 json 对象。但是您可以按照 Sean 的 anwser 手动进行操作。 Flask-Inputs 库只是我写的,目的是让它更简单。
猜你喜欢
  • 2023-04-04
  • 2016-05-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-24
  • 1970-01-01
相关资源
最近更新 更多