【问题标题】:Flask Admin Custom Form Validation for Multiple Fields?多个字段的 Flask Admin 自定义表单验证?
【发布时间】:2015-10-18 06:13:18
【问题描述】:

我一直打算创建一个基于多个字段值的自定义表单验证逻辑(在我的例子中,2 个字段来确保日期范围数据的完整性,即 start_time form_args 类的子类中的 form_args 属性的 validators 参数,但同样,这不是我想要的每个字段验证。

所以我的问题是:如何同时验证多个字段?

另外,我没有看到任何预保存钩子事件函数可以用来执行此操作。我知道on_model_change,但它是一个保存后的钩子,它会破坏验证的目的,将验证放在那里。进行预保存操作的适当方式是什么?

【问题讨论】:

标签: python flask sqlalchemy flask-wtforms flask-admin


【解决方案1】:

所以在试验和尝试了几种不同的方法之后,我进行多个表单字段验证的方式仍然是与on_model_change 挂钩,我知道它说事件挂钩是在进行更改后调用的 - 但是,因为它是被包装在事务中,可以引发任何异常来回滚事务。

这是我让它工作的示例代码。

from flask.ext.admin.form import rules
from wtforms import validators

class TimeWindowView(LoggedInView):
    column_filters = ('scheduled_start', 'scheduled_end')
    form_create_rules = [
        rules.Field('scheduled_start'),
        rules.Field('scheduled_end'),
    ]

    def on_model_change(self, form, model, is_created):
        # if end date before start date or end date in the past, flag them invalid
        if (form.scheduled_end.data <= form.scheduled_start.data or
            form.scheduled_end.data <= datetime.datetime.utcnow()):
            raise validators.ValidationError('Invalid schedule start and end time!')
        else:
            super().on_model_change(form, model, is_created)

【讨论】:

  • 另一种选择是使用 WTForms 验证机制。您可以在构造表单类后为其贡献一个函数,也可以提供一个带有validate_scheduled_end 函数的自定义基类。
  • @Joes 我如何在这样的验证器函数中访问model 实例?例如,我需要在 validate_email() 中检查 field.data != model.email,但 model 只能在 on_model_change() 中访问
  • 不幸的是,模型没有传递给验证器——您只能检查单个值。如果您需要模型,则必须在on_model_change 中进行。
  • 另外,如果您使用内联编辑,最好在使用前检查表单中是否有 'scheduled_end' 或检查它是否已创建
【解决方案2】:

您可以通过使用继承和自定义“validate_form”方法将自定义表单验证代码引入到您的烧瓶管理模型视图中,该方法在调用父“验证表单”之前合并您的验证代码。

如果您的验证逻辑发现问题,您的 validate_form 应显示适当的错误消息并返回 False,否则应通过运行原始的烧瓶管理员验证表单代码继续。

from flask_admin.contrib.sqla import ModelView
from flask import flash

class MyModelView(ModelView):
    """ My model admin model view """

    def validate_form(self, form):
        """ Custom validation code that checks dates """
        if form.start_time.data > form.end_time.data:
            flash("start time cannot be greater than end time!")
            return False
        return super(MyModelView, self).validate_form(form)

这是一个比 change_model_model 方法更自然的地方进行表单验证,它不应该关心模型逻辑,而不是表单验证逻辑。另外,请注意我们不需要使用异常并依赖于反转事务。我们只是在任何事务发生之前捕获错误,闪烁错误消息并优雅地返回“False”状态。

相关链接:

flask admin documentation

flask admin source code

【讨论】:

  • 可悲的是,当您在烧瓶管理员中的删除操作以及当您转到“创建”页面时,也会调用此方法。
  • @scythargon,您可以通过将额外的验证代码包装在 if is_form_submitted(): 中来解决这个问题(从 flask_admin.helpers 导入该函数)。
  • 如果您想将错误附加到特定表单字段而不是显示 Flash 消息,请参见此处:stackoverflow.com/a/19834740/328817
【解决方案3】:

这是另一个使用 form_base_class 让 wtforms 处理所有验证的解决方案:

from flask import flash
from flask_admin.contrib.sqla import ModelView
from flask_admin.form import BaseForm


class MyForm(BaseForm):
    def validate(self, *args, **kwargs):
        is_valid = super().validate(*args, **kwargs)

        if form.scheduled_end.data <= form.scheduled_start.data:
            flash("Invalid schedule start and end time", "error")

            # or instead of flash(), show the error at the scheduled_end field
            self.scheduled_end.errors.append("Should be after schedule start")
               
            is_valid = False

        return is_valid

class MyModelView(ModelView):
    form_base_class = MyForm

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-21
    • 1970-01-01
    • 2015-06-24
    • 2014-03-08
    • 1970-01-01
    • 1970-01-01
    • 2021-10-13
    • 2012-11-30
    相关资源
    最近更新 更多