简体   繁体   中英

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

The situation:

I am currently trying to validate an EditProfile form. In this, I need to be able to access the user variable that I have created in the view function in the wtforms which is located in forms.py, in order to validate that the name input is not the same as that which is the current value for the user and if it is not then run a query on it to check if it is in the system already to throw a validation error.

The code

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)

Here I have those if statements in order to try validating, however, it is not working to my satisfaction, thus wanting to move them into the forms validation, which is at the current moment of time.

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')

My aim

My aim is to somehow send the user variable to the forms.py to be able to validate it using a custom validation similar to:

    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.')

What I have done:

  1. I have tried placing the obj=user which works for auto filing values, but doesn't allow me to access the variable.
  2. I have tried to place the user-item into the 'g' variable from the flask, but this doesn't seem to work and doesn't seem like a good idea considering that multiple people using the app may end with the g variable being set at the same time.

A bit more info:

I am not able to use the current_user variable from flask-login as the person editing the profile will not be the user, but rather someone with a higher level on permissions chain. Hence why I think the best way is to send the user variable that has been created to the wtforms to process in the validation.

The Question:

The main question in all of this is how can I send a variable that has a query saved in it from the view to the form for validation, and if this is not possible what is the best way to validate this in a way that will allow the user to know what is going on without just throwing an internal error.

The answer was to send the variable to the form constructor and then from there set the variable as an attribute of the form constructor. ie

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM