user1592380
user1592380

Reputation: 36307

How to get Flask method working with or without token as a path element

I'm working to modify a cookiecutter Flask app. I'm trying to follow https://realpython.com/blog/python/handling-email-confirmation-in-flask/ to add email authorization.

The app sends a confirmation email. In this case the email contains a confirmation link that looks like:

http://127.0.0.1:5000/register/ImNsdWVtYXJpbmUxQG1haWxpbmF0b3IuY29tIg.CajQIA.Pn20l8bkpo3muh1Nk6TSguSoF0I

(which contains the embedded email '[email protected]' in the token.)

This works correctly with the register function (in the public blueprint):

@blueprint.route("/register/<token>", methods=['GET', 'POST'])
def register(token):
    form = RegisterForm(request.form, csrf_enabled=False)
    email = confirm_token(token)
    ....

In another part of my code I want to redirect the user to the register function and I've used the line:

return redirect(url_for('public.register'))

In this case, I'm not using a token! This results in:

Werkzeug.routing.BuildError BuildError: ('public.register', {}, None)

I assume this is because with the second method there is no token. Whats the best way to handle the possibility of either having or not having a token in the register function?

Full Traceback:

File "C:\envs\virtalenvs\flask_mini\lib\site-packages\flask\app.py", line 1836, in __call__
return self.wsgi_app(environ, start_response)
File "C:\envs\virtalenvs\flask_mini\lib\site-packages\flask\app.py", line 1820, in wsgi_app
response = self.make_response(self.handle_exception(e))
File "C:\envs\virtalenvs\flask_mini\lib\site-packages\flask\app.py", line 1403, in handle_exception
reraise(exc_type, exc_value, tb)
File "C:\envs\virtalenvs\flask_mini\lib\site-packages\flask\app.py", line 1817, in wsgi_app
response = self.full_dispatch_request()
File "C:\envs\virtalenvs\flask_mini\lib\site-packages\flask\app.py", line 1477, in full_dispatch_reques
rv = self.handle_user_exception(e)
File "C:\envs\virtalenvs\flask_mini\lib\site-packages\flask\app.py", line 1381, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "C:\envs\virtalenvs\flask_mini\lib\site-packages\flask\app.py", line 1475, in full_dispatch_request
rv = self.dispatch_request()
File "C:\envs\virtalenvs\flask_mini\lib\site-packages\flask_debugtoolbar\__init__.py", line 124, in dispatch_request
return view_func(**req.view_args)
File "C:\envs\r2\mini\myflaskapp\views\user.py", line 144, in confirm_email
return redirect(url_for('public.register'))
File "C:\envs\virtalenvs\flask_mini\lib\site-packages\flask\helpers.py", line 312, in url_for
return appctx.app.handle_url_build_error(error, endpoint, values)
File "C:\envs\virtalenvs\flask_mini\lib\site-packages\flask\app.py", line 1641, in handle_url_build_error
reraise(exc_type, exc_value, tb)
File "C:\envs\virtalenvs\flask_mini\lib\site-packages\flask\helpers.py", line 305, in url_for
force_external=external)
File "C:\envs\virtalenvs\flask_mini\lib\site-packages\werkzeug\routing.py", line 1678, in build
raise BuildError(endpoint, values, method)

Upvotes: 1

Views: 334

Answers (2)

lord63. j
lord63. j

Reputation: 4670

Yes, defaults can be specified, you can:

@blueprint.route("/register", defaults={'token': ''}, methods=['GET', 'POST'])
@blueprint.route("/register/<token>", methods=['GET', 'POST'])
def register(token):
    # do somethind here
    ....

Here is the documentation: URL Route Registrations

Upvotes: 1

Nick Frost
Nick Frost

Reputation: 490

One way to do this would be two separate routes.

@blueprint.route("/register/", methods=['GET', 'POST'])
@blueprint.route("/register/<token>", methods=['GET', 'POST'])
def register(token=None):
    form = RegisterForm(request.form, csrf_enabled=False)
    email = confirm_token(token)
    ....

Now url_for('public.register') should work as expected.

Upvotes: 1

Related Questions