如何在 wtforms 验证中使用视图函数中的查询变量

How to use a query variable from view function in wtforms validation

情况:

我目前正在尝试验证 EditProfile 表单。 在此,我需要能够访问我在位于 forms.py 的 wtforms 中的视图函数中创建的用户变量,以验证输入的名称与输入的名称不同用户的当前值,如果不是,则 运行 对其进行查询以检查它是否已在系统中以抛出验证错误。

代码

routes.py

    @bp.route('/edit_user/<name>', methods=['GET', 'POST']) 
    @login_required
    @group_required(['Master', 'Upper Management', 'Management'])
    def edit_user(name):
    
        user = User.query.filter_by(name=name).first()
        academy = Academy.query.filter_by(id=user.id).first()
        trained = TrainedIn.query.filter_by(teacher=user.id).all()
        
        form = EditProfileForm(obj=user)
    
        if form.validate_on_submit():
            
            if user.name != form.name.data:
                new = User.query.filter_by(name=form.name.data).first()
                if new is not None:
                    raise ValidationError('Name already in use.')
            
            if user.phone != form.phone.data:
                new = User.query.filter_by(phone=form.phone.data).first()
                if new is not None:
                    raise ValidationError('Phone number already in use.')
    
            if user.email != form.email.data:
                new = User.query.filter_by(email=form.email.data).first()
                if new is not None:
                    raise ValidationError('Email already in use.')
    
            
    
            return redirect(url_for('edit_user', name=user.name))
    
        elif not form.is_submitted():
    
            form.name.data = user.name
            form.phone.data = user.phone
            form.email.data = user.email
            form.position.data = user.position
            form.academy.data = academy.name
            form.trained.data = [t.name for t in trained] 
            
        return render_template('edit_user.html', title='Edit User',user=user, form=form)

这里我有那些 if 语句来尝试验证,但是,它并没有让我满意,因此想将它们移到表单验证中,这是在当前时间。

forms.py

class EditProfileForm(FlaskForm):

name = StringField('Full Name', validators=[DataRequired()])
phone = StringField('Phone Number', validators=[DataRequired()])
email = StringField('Email', validators=[DataRequired(), Email()])
position = SelectField('Position', validators=[DataRequired()], choices=[
    ('Upper Management', 'Upper Management'),
    ('Management', 'Management'), 
    ('Admin','Admin'), 
    ('Teacher','Teacher')])
academy = SelectField('Academy', validators=[DataRequired()], choices=[
    ('Alonso Martínez','Alonso Martínez'),
    ('Argüelles','Argüelles')
    ])
trained = SelectMultipleField('Trained to teach', choices=[
    ('General English', 'General English'),
    ('Exam', 'Exam'),
    ('Children', 'Children'),
    ('Level Test', 'Level Test')
    ])
submit = SubmitField('Confirm')

def validate_phone(self, phone):
    try:
        p = phonenumbers.parse(phone.data)
        if not phonenumbers.is_valid_number(p):
            raise ValueError()
    except (phonenumbers.phonenumberutil.NumberParseException, ValueError):
        raise ValidationError('Invalid phone number')

我的目标

我的目标是以某种方式将用户变量发送到 forms.py 以便能够使用类似于以下的自定义验证来验证它:

    def validate_name(self, name):
    if name != user.name:
        user1 = User.query.filter_by(name=name).first()
        if user1 is not None:
            raise ValidationError('Name already in use.')

我做了什么:

  1. 我试过放置用于自动归档的 obj=user 值,但不允许我访问变量。
  2. 我试图将用户项放入烧瓶中的 'g' 变量中,但是 这似乎行不通而且似乎不是个好主意 考虑到多人使用该应用程序可能以 g 结尾 同时设置变量。

更多信息:

我无法使用 flask-login 中的 current_user 变量,因为编辑配置文件的人不是用户,而是权限链上具有更高级别的人。因此,为什么我认为最好的方法是将已创建的用户变量发送到 wtforms 以在验证中处理。

问题:

所有这一切的主要问题是我如何将一个保存有查询的变量从视图发送到表单以进行验证,如果这不可能,那么验证它的最佳方法是什么一种让用户知道发生了什么而不只是抛出内部错误的方法。

答案是将变量发送到表单构造函数,然后从那里将变量设置为表单构造函数的属性。即

routes.py

form = EditProfileForm(obj=user.id)

forms.py

def __init__(self, obj, *args, **kwargs):
        self.user = int(obj)
        super(EditProfileForm, self).__init__(*args, **kwargs)