28

"werkzeug.routing.BuildError: Could not build url for endpoint 'success'. Did you forget to specify values ['name']?"

How to solve this error? I have tried many things but can't solve it by myself.

http_methods.py:

from flask import Flask, redirect, url_for, request
app = Flask(__name__)

@app.route('/success/<name>')
def success(name):
    return 'welcome %s' % name

@app.route('/login', methods=['POST', 'GET'])
def login():
    if request.method == 'POST':
        user = request.form['nm']
        return redirect(url_for('success', name = user))
    else:
        user = request.args.get('nm')
        return redirect(url_for('success', name = user))

if __name__ == "__main__":
    app.run(debug=True)

I get an error in the login method, that value of ['name'] is not specified; how to solve this error?

login.html:

<!DOCTYPE html>
<html lang="en">
    <body>
        <form action="http://127.0.0.1:5000/login" method="POST">
            <p>Enter name:</p>
            <p><input type="text" name="nm" value="nm"/></p>
            <p><input type="submit" value="submit"/></p>    
        </form>
    </body>
</html>

output:

  File "/Users/chirag.kanzariya/pythonprojects/v_python/lib/python3.7/site-packages/flask/helpers.py", line 345, in url_for
    force_external=external)
  File "/Users/chirag.kanzariya/pythonprojects/v_python/lib/python3.7/site-packages/werkzeug/routing.py", line 1776, in build
    raise BuildError(endpoint, values, method, self)
werkzeug.routing.BuildError: Could not build url for endpoint 'success'. Did you forget to specify values ['name']?
127.0.0.1 - - [29/Jan/2019 14:48:00] "GET /login?__debugger__=yes&cmd=resource&f=style.css HTTP/1.1" 200 -
127.0.0.1 - - [29/Jan/2019 14:48:00] "GET /login?__debugger__=yes&cmd=resource&f=jquery.js HTTP/1.1" 200 -
127.0.0.1 - - [29/Jan/2019 14:48:00] "GET /login?__debugger__=yes&cmd=resource&f=debugger.js HTTP/1.1" 200 -
127.0.0.1 - - [29/Jan/2019 14:48:00] "GET /login?__debugger__=yes&cmd=resource&f=ubuntu.ttf HTTP/1.1" 200 -
127.0.0.1 - - [29/Jan/2019 14:48:00] "GET /login?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 200 -
127.0.0.1 - - [29/Jan/2019 14:48:00] "GET /login?__debugger__=yes&cmd=resource&f=console.png HTTP/1.1" 200 -

I am using python 3.7 and flask 1.0.2 version right now.

Robert
  • 7,394
  • 40
  • 45
  • 64
Chirag Kanzariya
  • 377
  • 1
  • 4
  • 11
  • Try remove this part: else: user = request.args.get('nm') return redirect(url_for('success', name = user)) – gittert Jan 29 '19 at 09:47
  • UnboundLocalError: local variable 'user' referenced before assignment.-@gittert – Chirag Kanzariya Jan 30 '19 at 03:44
  • I have the same error. This code example comes form the following tutorial: https://www.tutorialspoint.com/flask/flask_url_building.htm I've tested the code in response bellow of @gittert without success. Any ideas? – eduardosufan Mar 13 '19 at 14:34
  • I'm wondering what the output of both user variables are? user = request.form['nm'] and user = request.args.get('nm') – gittert Mar 13 '19 at 14:58
  • related - https://stackoverflow.com/questions/51234212/werkzeug-routing-builderror-could-not-build-url-for-endpoint – cardamom Dec 14 '22 at 09:59

7 Answers7

9

Have a look at this. In your login function I added a render_template for the first GET request when opening the login page. This will probably also prevent the error you're getting now. Bear in mind this does not contain any error handling, like what happens if user is unknown in your login procedure.

@app.route('/success/<name>')
def success(name):
    return 'welcome %s' % name

@app.route('/login', methods=['POST', 'GET'])
def login():
    if request.method == 'POST':
        user = request.form['nm']
        return redirect(url_for('success', name = user))

    return render_template(login.html)

if __name__ == "__main__":
    app.run(debug=True)
gittert
  • 1,238
  • 2
  • 7
  • 15
  • Even if this does not completely answer my script issue, it made me think about the importance of a correct `@app.route(whatever)` and a correct `return #whatever` always available for the function `def whatever (): #whatever function with a correct return` (inside the boolean conditions or the error handling try/except, you always need to return something). So give a point to @gittert because the answer here guided me to the answer for my code. – Corina Roca May 14 '21 at 13:39
4

You need to add in the else section (GET), the html code for your login.

from flask import Flask, request, render_template, redirect, url_for
app = Flask(__name__)

@app.route('/success/<name>')
def success(name):
    return 'welcome %s' % name

@app.route('/login',methods = ['POST', 'GET'])
def login():
    if request.method == 'POST':
        user = request.form['nm']
        return redirect(url_for('success',name = user))
    else:
        return render_template('login.html')

if __name__ == '__main__':
    app.run(debug = True)
eduardosufan
  • 1,441
  • 2
  • 23
  • 51
  • 1
    that doesnt really differ from my answer below (except for the typo). Why would your answer work and mine would not? – gittert Mar 14 '19 at 14:27
4

The tutorial from which this code originates has a logical flaw, identified and rectified by the initial two contributors gittert and eduardosufan. This vexed me too, but I couldn't work out whether it was just my poor understanding of Flask, or whether there was genuinely a problem with the tutorial, until I came across this Stack Overflow question, which confirmed the latter.

Specifically, the logic initially checks for a POST request. If it's not that, it assumes a GET - and crucially, also the value of nm. Here's the flaw: if the user has not yet entered a name, then its value will be None, for which Werkzeug can't create a route, and that prevents the page from even being loaded - chicken and egg.

1

The anchor tag in the HTML file being rendered should reference the function that it is being directed to. For example following the code snippet below, if we want to reference index in HTML, the flask app "app.py" must contain a function called index.

I have added the about function to clarify what I mean.

from flask import Flask, render_template

app = FLASK(__name__)

@app.route('/')
def index():
    return render_template('home.html')

@app.route('/')
def about():
    return render_template('about.html')

<a href="{{url_for('index')}}">Index</a>
to 
<a href="{{url_for('about')}}">Index</a>
0

You're trying to access the login directly. You first have to open the html page. then it accesses the value. try this fix and open the html page first

@app.route('/login',methods=["POST","GET"])
def login():
    if request.method=="POST":
        user=request.form["nm"]
    else:
        user=request.args.get("nm")
    if user:
        return redirect(url_for('success', name = str(user)))
    else:
        return "go to the form"
0

There's nothing wrong with your code, all you need to do is navigate to the folder containing your .py code and the html file containing the form (ensuring they are in the same folder) and run the html file, complete the form and submit. the server takes care of the connection between the python code and html code using the link passed in action. I hope it helps.I battled with this very same issue, all suggested responses work only if you run your html code first not just the .py script.

0

For blueprint routes as a module check url_for function in HTML template

<a href="{{url_for('index')}}">Index</a>
to 
<a href="{{url_for('auth.index')}}">Index</a>