Mr Mohen Mr Mohen - 2 months ago 6
Python Question

why does function url_for() in Flask produced this error?

When I use flask, in my first template(a.html) I wrote:

{{url_for('auth.confirm', token=token, _external=True)}}


It gave the right site:
/auth/confirm/<token>


But in another:
{{url_for('auth.forget', token=token, _external=True)}}


It gave me a site like this:
/auth/forget?token=<token>


What makes the diffence?


Codes here:

@auth.route('/forget', methods=['GET', 'POST'])
def forget():
form=ForgetPasswordForm()
if form.validate_on_submit():
user=User.query.filter_by(email=form.email.data).first()
if user:
token=user.generate_forget_token()
send_email(user.email, 'Reset your password', 'auth/email/forget', token=token)
return redirect(url_for('main.index'))
flash("Email is not exist")
return render_template('auth/forget.html',form=form)

@auth.route('/forget/<token>', methods=['GET', 'POST'])
def forget_reset(token):
try:
email=User.confirm_forget(token)
except:
return render_template('404.html')
form=PasswordOnlyForm()
if form.validate_on_submit():
user=User.query.filter_by(email=email).first()
user.password=form.password.data
db.session.add(user)
db.session.commit()
flash('Succeed, now login!')
return redirect('auth/login')
return render_template('auth/PasswordOnly.html',form=form)

Answer

The underlying functions are expecting different urls.

In the first case, the flask routing decorator looks like:

@app.route('/auth/confirm/<token>')
def confirm(token):

In the second, the token is not specified, and therefore passed as a query parameter.

@app.route('/auth/forget/')
def forget():

You'll also need to be careful about which function you are calling. In your example above, you have two functions: forget and forget_reset which have two different behaviors.

@app.route('/auth/forget/')
def forget():
    pass

@auth.route('/forget/<token>', methods=['GET', 'POST'])
def forget_reset(token):
    pass

Now you call them slightly differently. If you call forget:

<a href="{{url_for('forget', token='hello')}}">Calling Forget</a>

http://127.0.0.1:5000/forget?token=hello

And if you call forget_reset:

<a href="{{url_for('forget_reset', token='hello')}}">Calling Forget Reset</a>

http://127.0.0.1:5000/forget/hello