【问题标题】:Using same form to create and update but different validation logic使用相同的表单创建和更新但不同的验证逻辑
【发布时间】:2017-06-23 16:13:29
【问题描述】:

我有一个 FlaskForm 类,我在其中验证字段值是否已在系统中,并在需要时引发 ValidationError。

def validate_username(self, username_field):
    if User.query.filter_by(username=username_field.data).first():
        raise ValidationError("This username is already taken.")

对于用户,我实际上不得不使用不同的验证来创建一个单独的 Form 类来更新模型。

def validate_username(self, username_field):
    if current_user.username != username_field.data:
        if User.query.filter_by(username=username_field.data).first():
            raise ValidationError("Cannot change username to this as it already is taken.")

但是现在我需要使用另一个我无法从 Form 类访问的模型,因为它与用户无关(它取决于正在编辑的记录)。我不确定如何进行此验证,如果可能的话,我不希望这些模型有两个 FlaskForm 类。

有什么方法可以将某些验证方法仅应用于某个操作(创建与更新),还是我必须为每个具有唯一字段的模型编写多个 FlaskForm 类?

我认为这种设计模式必须经常出现,但找不到处理它的好例子。

【问题讨论】:

  • 你能澄清一下吗?您是在问是否可以为每个模型使用一个 FlaskForm 类,或者您需要创建一个单独的 FlaskForm 来为每个模型添加和编辑案例?
  • 我希望每个模型只使用一个 FlaskForm,但是在创建和编辑时我需要不同的验证。我想知道是否有一种方法可以做到这一点,而无需为每个模型设置两个 FlaskForm 类。此外,即使每个模型确实需要两个 FlaskForm 类,我也不确定如何验证现有记录中的信息并将其与输入到表单中的新信息进行比较以确定它是否已使用 FlaskForm 自定义验证进行了更改(这样做需要在视图中完成吗?如果是,如何在validate_on_submit()成功后再次引发ValidationError?)。

标签: python flask wtforms flask-wtforms


【解决方案1】:

每个模型可以使用一个 FlaskForm。这是 User 模型的表单类:

class UserForm(FlaskForm):
    """
    Form to add or edit a user
    """

    username = StringField('username', validators=[DataRequired()])
    password = StringField('password', validators=[DataRequired()])
    ...

然后在你的views.py中你这样做:

@app.route('/user/add', methods=['GET', 'POST'])
@login_required
def add_user():
    """
    Add a user to the database
    """

    add_user = True

    form = UserForm()
    if form.validate_on_submit():
        user = User(...)
        ...
        # store the user in the db

    return render_template('/.../user.html', action="Add",
                   add_user=add_user, form=form,
                   title="Add User")


@app.route('/user/edit/<int:id>', methods=['GET', 'POST'])
@login_required
def edit_user(id):
    """
    Edit a user
    """

    add_user = False

    user = User.query.get_or_404(id)
    form = UserForm(obj=user)

    if form.validate_on_submit():
        user.username = form.username.data
        ...
        # Here you can check whether new name of the user corresponds
        # already existing user
        ...


return render_template('/.../user.html', action="Edit",
                       add_user=add_user, form=form,
                       user=user, title="Edit User")

这就是你的 user.html 模板的样子:

<div class="...">
    {% if add_user %}
        <h1>Add User</h1>
    {% else %}
        <h1>Edit User</h1>
    {% endif %}
    <br/>
    <form action="" method="post" class="form">
      {{ form.hidden_tag() }}
      {{ wtf.form_errors(form, hiddens="only") }}
      {{ wtf.form_field(form.username) }}
      {{ wtf.form_field(form.password) }}
      ...

      <div class="form-group">
        <input type="submit" value="Submit" class="btn btn-default">
        <a href="{{ url_for('app.list_users') }}" class="btn btn-default">
          Back 
        </a>
      </div>
    </form>
</div>

您使用布尔值add_user 来区分添加或编辑现有用户。可能不需要为此编写单独的验证器。

希望这会有所帮助。

【讨论】:

  • 我在哪里引发验证错误,以便错误像 FlaskForm 类中的方法一样显示在表单中?
  • @Dan 如果发生错误,您可以使用flash 方法。用户将通过这个{{ wtf.form_errors(form, hiddens="only") }} 将html模板中的错误。
  • @Dan 我也认为您可以使用一种验证器方法并在那里对用户名进行所有检查。
  • 这是自定义验证器。我可以根据创建或更新使它们的行为有所不同吗?
  • @Dan 老实说,我不知道。我从来没有在我的实践中尝试过。但是我提出的方法应该可以解决您的问题。
猜你喜欢
  • 2013-03-09
  • 2015-04-20
  • 2020-08-15
  • 1970-01-01
  • 1970-01-01
  • 2014-05-15
  • 1970-01-01
  • 1970-01-01
  • 2019-04-14
相关资源
最近更新 更多