shitoujizu shitoujizu - 4 months ago 45
Python Question

Flask Blueprint url_for BuildError when using add_url_rule

I am stuck in blueprint when I am trying to use flask blueprint in the way of

add_url_rule


Here's my flask project structure:

myapp
... __init__.py
... app.py
... model
... static
... views
...... main.py
... templates
...... base.html
...... results.html


In main.py,Here is my code:

from flask import Flask, url_for, Blueprint
main_bp = Blueprint('main', __name__)

def home():
return redirect(url_for('main.results'))

def results():
# some code
return render_template('result.html')


and In my app.py, Here's the code:

from myapp.views.main import main_bp

app.register_blueprint(main_bp)

app.add_url_rule('/', view_func=main.home)

app.add_url_rule('/results', view_func=main.results, methods=['POST', 'GET'])


when I am visiting the index page, I always got the following error message:

Traceback (most recent call last):
File "/Users/deamon/venv/src/staticngclient/staticng_client/middlewares/wsgi.py", line 25, in __call__
return app(environ, start_response)
File "/Users/deamon/venv/src/daeprofiling/dae_profiling/middleware.py", line 24, in __call__
return self.app(environ, start_response)
File "/Users/deamon/venv/src/doubancommonlib/douban/common/middleware/content_filter.py", line 18, in __call__
app_iter = self.application(environ, response.start_response)
File "/Users/deamon/dae/app/web.py", line 77, in __call__
return handler(environ, start_response)
File "/Users/deamon/Projects/dae/dae/handlers/__init__.py", line 65, in __call__
return self.app(environ, start_response)
File "/Users/deamon/Projects/dae/dae/handlers/web.py", line 46, in __call__
return self._app(*a, **kw)
File "/Users/deamon/venv/lib/python2.7/site-packages/flask/app.py", line 1836, in __call__
return self.wsgi_app(environ, start_response)
File "/Users/deamon/venv/lib/python2.7/site-packages/flask/app.py", line 1820, in wsgi_app
response = self.make_response(self.handle_exception(e))
File "/Users/deamon/venv/lib/python2.7/site-packages/flask/app.py", line 1403, in handle_exception
reraise(exc_type, exc_value, tb)
File "/Users/deamon/venv/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app
response = self.full_dispatch_request()
File "/Users/deamon/venv/lib/python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/Users/deamon/venv/lib/python2.7/site-packages/flask/app.py", line 1381, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/Users/deamon/venv/lib/python2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request
rv = self.dispatch_request()
File "/Users/deamon/venv/lib/python2.7/site-packages/flask/app.py", line 1461, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/Users/deamon/kiwi/views/main.py", line 19, in home
return redirect(url_for('main.results'))
File "/Users/deamon/venv/lib/python2.7/site-packages/flask/helpers.py", line 312, in url_for
return appctx.app.handle_url_build_error(error, endpoint, values)
File "/Users/deamon/venv/lib/python2.7/site-packages/flask/app.py", line 1641, in handle_url_build_error
reraise(exc_type, exc_value, tb)
File "/Users/deamon/venv/lib/python2.7/site-packages/flask/helpers.py", line 305, in url_for
force_external=external)
File "/Users/deamon/venv/lib/python2.7/site-packages/werkzeug/routing.py", line 1678, in build
raise BuildError(endpoint, values, method)
BuildError: ('main.results', {}, None)


also, in mye templates, such as base.html or results.html, when I am using

<a class="navbar-brand" href="{{ url_for('main.home') }}">kiwi</a>


the same error occurs.

Can someone help?

Answer

Ok, so the first problem I see that is even though you're trying to use blueprint you're not actually doing anything with it.

Yeah, in the line main_bp = Blueprint('main', __name__) you create it, but after that you don't actually register any url endpoints for it and instead try to do it via imports in the main app.

Because you don't actually register the endpoints in the blueprint but try to create redirect for it by calling main.results with prefix to the blueprint 'main' your url_for function fails.

This is how your code would look with proper use of blueprints

blueprint

from flask import Flask, url_for, Blueprint
main_bp = Blueprint('main', __name__)

@main_bp.route('/') 
def home():
    return redirect(url_for('main.results'))

@main_bp.route('/results') 
def results():
    # some code
    return render_template('result.html')

and app.py

from myapp.views.main import main_bp

app.register_blueprint(main_bp)

Or if you want to use add_url_rule (which works exactly like the decorator) just use main_bp.add_url_rule(...) in the blueprint file.

Working example with add_url_rule

Blueprint file

from flask import Flask, url_for, Blueprint, redirect, render_template
main_bp = Blueprint('main', __name__)

def home():
    return redirect(url_for('main.results'))

def results():
    # some code
    return 'some results'

main_bp.add_url_rule('/', view_func=home)
main_bp.add_url_rule('/results', view_func=results)

app file

from flask import Flask
import bp

app = Flask(__name__)


app.register_blueprint(bp.main_bp)



if __name__ == '__main__':
    app.run()