New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
blueprint options from register_blueprint #612
Comments
Why not to use |
Unfortunately, not. According to the docs, that should work because it returns the url relative to the blueprint. When I actually test it out, however, I get different behavior. Consider this code:
And
When I hit Instead, for both endpoints, it prints out
The url printed out would be This seems to be unintended behavior for a blueprint that has been attached to multiple prefixes in an application. |
Ok, just checked the source. I have no clue what to do.
and then add a custom name while registering like this:
I think this is more elegant than other solutions and not so difficult to implement. We could simply defer the initialization of |
Since Blueprint is a subclass of |
Actually, I'm pretty sure it's possible. You can simply do:
But do blueprints need to access The problem you're having is this: Flask uses that My idea banally makes you able to define the name at registration time, thus you can use the same blueprint object twice by changing that unique identifier. This would allow to use |
Oh, it would work mechanically - never said it wouldn't. It's a question of the semantics of leaving an object partially init'ed after instantiation. Somehow that seems... wrong. :) The problem is that Regardless, after noodling on this a bit - and becoming very familiar with the internals of flask - I think the best, least abrasive option is to simply use the factory pattern above. I may take a whack at writing code that allows access to the options passed in during blueprint registration at a later time. |
Ok, you're indeed right ;-) BTW, you don't have to use |
I'm not clear on how this was resolved. I am trying to have the same blueprint registered with multiple prefixes, and to have render various non-relative URL's I need to generate use the prefix_url to generically (i.e. I only need one function to handle all of the prefixes). At this point I'm left with extracting the prefix from the request object and/or not using blueprint prefixes and just registering my functions with the "prefix" being a parameter for the function. Both seem to violate the principles of what blueprints are ostensibly about. |
Well, this is still unresolved. |
You can already do this easily. The basic version is this: from flask import Flask, Blueprint, url_for
bp = Blueprint('whatever', __name__)
@bp.route('/')
def index(name):
return 'I am %s (%s)' % (name, url_for('.index', name=name))
app = Flask(__name__)
app.register_blueprint(bp, url_prefix='/foo1', url_defaults={'name': 'Foo1'})
app.register_blueprint(bp, url_prefix='/foo2', url_defaults={'name': 'Foo2'})
c = app.test_client()
assert c.get('/foo1/').data == 'I am Foo1 (/foo1/)'
assert c.get('/foo2/').data == 'I am Foo2 (/foo2/)' The more complicated version that gives a nicer API: from flask import Flask, Blueprint, url_for, g
bp = Blueprint('whatever', __name__)
@bp.url_defaults
def bp_url_defaults(endpoint, values):
name = getattr(g, 'name', None)
if name is not None:
values.setdefault('name', name)
@bp.url_value_preprocessor
def bp_url_value_preprocessor(endpoint, values):
g.name = values.pop('name')
@bp.route('/')
def index():
return 'I am %s (%s)' % (g.name, url_for('.index'))
app = Flask(__name__)
app.register_blueprint(bp, url_prefix='/foo1', url_defaults={'name': 'Foo1'})
app.register_blueprint(bp, url_prefix='/foo2', url_defaults={'name': 'Foo2'})
c = app.test_client()
assert c.get('/foo1/').data == 'I am Foo1 (/foo1/)'
assert c.get('/foo2/').data == 'I am Foo2 (/foo2/)' |
As a second step you can use the values passed in the view args then to find specific blueprint configuration etc. If you need that information available outside the routing system you can create multiple blueprint objects with different names from a factory function. |
One of the ugliest hacks I've ever seen. It should be easier. |
I am accepting a nice proposal on how a nicer solution is supposed to look like. Also not sure how that's a hack, it was designed to work this way. |
(There already is a way to keep blueprints apart: their name. You can just generate a blueprint in a factory and then refer to the blueprint through closures. I don't quite see where the issue is to be honest) |
URL pre-processors should work as URL pre-processors, not as a strange way to create identifiers. That's IMHO a hack. Do you want some proposals? Here you are.
|
I'd like to be able to bind the same blueprint to two different url_prefix's. There aren't a lot of good ways to do it. The only way I could figure out how to make it work write was to either a) treat the url_prefix as an argument in the route:
or to have all the handlers be tied to one giant closure:
or to have a method which procedurally adds the routes:
It seems like being able to bind a blueprint to multiple places ought to be the default capability for blueprints, but it feels like it's a special case that breaks odd things in odd places, and generally requires extra work. Either I'm doing it wrong or there is an opportunity to make this far more elegant. |
I've written a flask app that uses a blueprint to implement an API. When I create the server, I use register_blueprint to make the api available. I added a url_prefix parameter as a parameter to the call to register_blueprint. Thus, in theory, I could add multiple versions of this api for different instances.
As part of the blueprint, there is a particular method that needs to send a redirect to the requesting browser. This redirect is to another part of the blueprint. The problem is that url_prefix does not seem to be available within the request or current_app objects. At least, not in anyway that I've been able to see.
Here's some code that illustrates the problem:
And here's the part where the app server is created:
The correct behaviors would be to go to "/instance1/auth/login" or "/instance2/auth/login." The problem is that the redirect code doesn't have a way (that I can see) of getting the url_prefix that was used to register the blueprint.
My initial thought was to see if I could get a hold of the Blueprint object that was registered on the app and maybe it would have the url_prefix that I could prepend on the redirect line. This would look something like:
The problem is that the way blueprint is stored in Flask.register_blueprint (https://github.com/mitsuhiko/flask/blob/master/flask/app.py#L867):
means that each separate registration of blueprint shares the same blueprint object and url_prefix may not be valid between registrations. E.g. it's not enough to simply set url_prefix on the blueprint.
My solution to this was to create a factory method:
and in the server creation code:
This works, and I have access to url_prefix in the instances. It wasn't critical for my project, but it was a surprising property of Flask.
It seems awkward, and a violation of the principle-of-least surprise. Why wouldn't the blueprint methods have access to the url_prefix (or any other options passed in during blueprint registration)? Are there any more elegant solutions than the one above?
The text was updated successfully, but these errors were encountered: