如果字段数据未更改,WTForms 将跳过验证

WTForms skip validation if field data is unchanged

我有一个 Flask 网络应用程序可以管理所有信息亭的信息。我为信息亭的信息创建了一个 WTForms 对象 (forms.py):

class KioskForm(FlaskForm):
    kiosk_name = StringField('Kiosk Name', validators=[DataRequired()])
    kiosk_site = SelectField('Kiosk\'s Site', validators=[DataRequired()])
    kiosk_location = StringField(
        'Kiosk\'s Location', validators=[DataRequired()])
    kiosk_ip = StringField('IP Address', validators=[
        IPAddress(), DataRequired()])
    kiosk_mac = StringField('MAC Address', validators=[DataRequired()])
    submit = SubmitField('Submit')

    def validate_kiosk_name(self, kiosk_name):
        kiosk = db.session.query(KioskConf).filter_by(
            equipment_name=self.kiosk_name.data).first()

        if kiosk is not None:
            raise ValidationError('Kiosk Name existed.')

假设我想编辑现有信息亭的信息 (routes.py):

@app.route('/edit_kiosk/<kiosk_name>', methods=['GET', 'POST'])
def edit(kiosk_name):
    data = db.session.query(KioskConf).filter_by(
        equipment_name=kiosk_name).first()

    form = KioskForm(kiosk_name=data.equipment_name,
                     kiosk_location=data.equipment_location,
                     kiosk_ip=data.equipment_ip,
                     kiosk_mac=data.equipment_mac)
    ... ...

我想做的是:如果有人将 kiosk 的名称更改为另一个现有名称,它会抱怨该名称已经存在。验证在 forms.py.

但是,一个问题是,如果我编辑了一个现有的信息亭,也许更改了 ip 地址,但名称保持不变,提交后仍然抱怨该名称已经存在。这里的名称验证肯定有问题。

如果名称未更改,如何使 WTForms 跳过名称验证?

我真的无法在本地 运行 这个逻辑并确认它有效,但我过去实施过类似的解决方案。试试这个,让我知道它是否对你有帮助。干杯, -安德鲁


def initializeKioskForm(edit_boolean):
    # only validate if edit_boolean is false
    if edit_boolean == False:
        kiosk = db.session.query(KioskConf).filter_by(
            equipment_name=self.kiosk_name.data).first()
        if kiosk is not None:
            raise ValidationError('Kiosk Name existed.')
    
    class KioskForm(FlaskForm):
        kiosk_name = StringField('Kiosk Name', validators=[DataRequired()])
        kiosk_site = SelectField('Kiosk\'s Site', validators=[DataRequired()])
        kiosk_location = StringField(
            'Kiosk\'s Location', validators=[DataRequired()])
        kiosk_ip = StringField('IP Address', validators=[
            IPAddress(), DataRequired()])
        kiosk_mac = StringField('MAC Address', validators=[DataRequired()])
        submit = SubmitField('Submit')

    return KioskForm


from forms import initialize_controller_form

@app.route('/edit_kiosk/<kiosk_name>', methods=['GET', 'POST'])
def edit(kiosk_name):
    data = db.session.query(KioskConf).filter_by(
        equipment_name=kiosk_name).first()

    KioskForm = initializeKioskForm(edit_boolean=True)
    form = KioskForm(kiosk_name=data.equipment_name,
                        kiosk_location=data.equipment_location,
                        kiosk_ip=data.equipment_ip,
                        kiosk_mac=data.equipment_mac)

所以我想出了一个完全符合我要求的解决方案,尽管最终代码库稍微笨拙。

forms.py中添加一个初始化器来存储原始字段数据,并用于比较新数据:

class KioskForm(FlaskForm):
    kiosk_name = StringField('Kiosk Name', validators=[DataRequired()])
    kiosk_site = SelectField('Kiosk\'s Site', validators=[DataRequired()])
    kiosk_location = StringField(
        'Kiosk\'s Location', validators=[DataRequired()])
    kiosk_ip = StringField('IP Address', validators=[
        IPAddress(), DataRequired()])
    kiosk_mac = StringField('MAC Address', validators=[DataRequired()])
    submit = SubmitField('Submit')

    # Initialiser
    def __init__(self, original_name, *args, **kwargs):
        super(KioskForm, self).__init__(*args, **kwargs)
        self.original_name = original_name

    # Changed to compare the old & new data
    def validate_kiosk_name(self, kiosk_name):
        if kiosk_name.data != self.original_name:
            kiosk = db.session.query(KioskConf).filter_by(
                equipment_name=self.kiosk_name.data).first()
            if kiosk is not None:
                raise ValidationError('Kiosk ID existed.')

并在routes.py中,将原名填入original_name:

@app.route('/edit_kiosk/<kiosk_name>', methods=['GET', 'POST'])
def edit(kiosk_name):
    data = db.session.query(KioskConf).filter_by(
        equipment_name=kiosk_name).first()

    form = KioskForm(kiosk_name=data.equipment_name,
                     kiosk_location=data.equipment_location,
                     kiosk_ip=data.equipment_ip,
                     kiosk_mac=data.equipment_mac,
                     original_name=data.equipment_name
)
    ... ...