Using Flask Blueprints, how to fix url_for from br

2019-04-06 15:22发布

问题:

Inside of a flask blueprint, i have:

frontend = Blueprint('frontend', __name__)

and the route to my index function is:

@frontend.route('/')
def index():
  #code

This works fine but, I am trying to add a subdomain to the route, like so:

@frontend.route('/', subdomain='<var>')
def index(var):

But this breaks the app and the browser spits out (amongst other things):

werkzeug.routing.BuildError
BuildError: ('frontend.index', {}, None)

frontend.index is called out in my code in a few places in a url_for('frontend.index')

How can I get the url_for to work when I'm including a subdomain? The only thing in the documents I can find and I think might be relevant is this under http://flask.pocoo.org/docs/api/:

To integrate applications, Flask has a hook to intercept URL build errors through Flask.build_error_handler. The url_for function results in a BuildError when the current app does not have a URL for the given endpoint and values. When it does, the current_app calls its build_error_handler if it is not None, which can return a string to use as the result of url_for (instead of url_for‘s default to raise the BuildError exception) or re-raise the exception. An example:

def external_url_handler(error, endpoint, **values):
    "Looks up an external URL when `url_for` cannot build a URL."
    # This is an example of hooking the build_error_handler.
    # Here, lookup_url is some utility function you've built
    # which looks up the endpoint in some external URL registry.
    url = lookup_url(endpoint, **values)
    if url is None:
        # External lookup did not have a URL.
        # Re-raise the BuildError, in context of original traceback.
        exc_type, exc_value, tb = sys.exc_info()
        if exc_value is error:
            raise exc_type, exc_value, tb
        else:
            raise error
    # url_for will use this result, instead of raising BuildError.
    return url

app.build_error_handler = external_url_handler

However, I am new to python (and programming) and can not understand where I would put this code or how I would get that function to call when a builderror occurs.

Any insight would be greatly appreciated :)

回答1:

First, to use subdomains you need to have a value for the SERVER_NAME configuration:

app.config['SERVER_NAME'] = 'example.net'

You have a view like this:

frontend = Blueprint('frontend', __name__)
@frontend.route('/', subdomain='<var>')
def index(var):
    return ...

In order to reconstruct the URL to this view, Flask needs a value for var. url_for('frontend.index') will fail since it does not have enough values. With the above SERVER_NAME, url_for('frontend.index', var='foo') will return http://foo.example.net/.



回答2:

Add blueprint name in url_for. Example:

url_for('pay_sermepa.sermepa_cancel', _external=True)
  • pay_sermepa: blueprint name
  • sermepa_cancel: route


回答3:

I don't think this is an issue with Flask.

You are providing two functions with the same method name:

@frontend.route('/')
def index():
  #code

and

@frontend.route('/', subdomain='<var>')
def index(var):

They are wrapped differently but when flask.build_url is called, it is throwing because of overloaded function name. This seems incorrect on first glance.

Try providing a different function name for the second one like

@frontend.route('/', subdomain='<var>')
def index_var(var):

This may solve your issue. I haven't tested it though.