Flask: getting url_prefix for blueprint in view - python

I have a blueprint with one view. I would like to get url_prefix of blueprint inside view. Unfortunately test.url_prefix returns None. Is there any other way?
app.register_blueprint(test_blueprint, url_prefix = "/test")
#test.route("/task", methods=["GET"])
def task_view(user):
task_url = test.url_prefix + "/task" # test.url_prefix is None ??

Yes.
In Flask the route path of the current view is contained in the url_rule.rule subproperty of the request variable.
So you can do the following:
from flask import request
...
test_blueprint = Blueprint('test', __name__, url_prefix='/test')
...
#test_blueprint.route("/task", methods=["GET"])
def task_view(user):
task_url = request.url_rule.rule
....
app.register_blueprint(test_blueprint)
The value of task_url will be:
/test/task
as desired.

from flask import Blueprint
admin_panel = Blueprint('admin', __name__, template_folder='templates', static_folder='static')
#admin_panel.route('/')
def index():
url_prefix=admin_panel.name
print(url_prefix)
pass

Related

Overwrite route in flask blueprint

There is a blueprint with a lot of useful routes defined, but I have no control over it (can not change it's code in any way)
Trying to reuse it in a different app but one of the blueprint's endpoints must be overloaded. How can I achieve that?
I tried just adding a new route to blueprint on top of the existing one:
#blueprint.route('/my/route', methods=['PUT', 'POST'])
def my_new_view_func(program, project):
# some new behavior for the endpoint
As the result there is duplicate url_rule in app.url_map.iter_rules():
<Rule '/my/route' (PUT, POST) -> my_view_func>,
<Rule '/my/route' (PUT, POST) -> my_new_view_func>,
and when requesting /my/route old viewer my_view_func gets executed
Can I somehow get rid of the old url rule? Or maybe there is a better way to overwrite the route?
There are 2 solutions which I found. First:
from flask import Flask, Blueprint
simple_page = Blueprint('simple_page', __name__, )
#simple_page.route('/my/route/')
def my():
# for example it's a registered route somewhere...
return 'default'
#simple_page.route('/my/route/')
def new_my():
# new endpoint / should works instead my()
return 'new'
# map of views which we won't register in Flask app
# you can store this somewhere in settings
SKIP_VIEWS = (
# route, view function
('/my/route/', my, ),
)
class CustomFlask(Flask):
def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
# Flask registers views when an application starts
# do not add view from SKIP_VIEWS
for rule_, view_func_ in SKIP_VIEWS: # type: str, func
if rule_ == rule and view_func == view_func_:
return
return super(CustomFlask, self).add_url_rule(rule, endpoint, view_func, **options)
app = CustomFlask(__name__)
app.register_blueprint(simple_page)
app.run(debug=True)
Second way:
two.py - default blueprint with endpoint
from flask import Blueprint
bp_two = Blueprint('simple_page2', __name__, )
#bp_two.route('/my/route/')
def default():
return 'default'
test.py - your blueprint + app
from flask import Flask, Blueprint
from two import bp_two
your_bp = Blueprint('simple_page', __name__, )
#your_bp.route('/my/route/')
def new_route():
return 'new'
app = Flask(__name__)
# register blueprint and turn off '/my/route/' endpoint
app.register_blueprint(bp_two, **{'url_defaults': {'/my/route/': None}})
app.register_blueprint(your_bp)
app.run(debug=True)
Run app. Open /my/route/. You will see that default endpoint wasn't add/works.
Hope this helps.

Flask: get current blueprint webroot

I am building a Flask app with a blueprint mounted on two different endpoint (one is a legacy alias to the other).
In my blueprint class:
ldp = Blueprint('ldp', __name__)
#ldp.route('/<path:uuid>', methods=['GET'])
#ldp.route('/', defaults={'uuid': None}, methods=['GET'],
strict_slashes=False)
def get_resource(uuid):
# Route code...
In my main server code:
app = Flask(__name__)
app.config.update(config['flask'])
app.register_blueprint(ldp, url_prefix='/new_ep')
# Legacy endpoint. #TODO Deprecate.
app.register_blueprint(ldp, url_prefix='/old_ep')
How can I get the actual URL of the request up to the /old_ep or /new_ep part in the route method, e.g. http://localhost:5000/new_ep?
So far I have used
request.host_url + request.path.split('/')[1]
but it looks quite inelegant and possibly error-prone. I would like to use the information from the blueprint setup if possible.
Thanks for your help.
EDIT: I could get to the Blueprint instance from within the request with
current_app.blueprints[request.blueprint]
and I was hoping that the url_prefix attribute that I set when registering the blueprint was there, but it is None instead. As I read from the documentation for the supposedly related iter_blueprints() method, apparently these blueprints are listed without regard of how many times and with which parameters they were registered. Too bad.
Here is a full working example to get the idea based off issue 612
from flask import Flask, Blueprint, url_for, request, g
bp = Blueprint('whatever', __name__)
#bp.url_defaults
def bp_url_defaults(endpoint, values):
url_prefix = getattr(g, 'url_prefix', None)
if url_prefix is not None:
values.setdefault('url_prefix', url_prefix)
#bp.url_value_preprocessor
def bp_url_value_preprocessor(endpoint, values):
g.url_prefix = values.pop('url_prefix')
#bp.route('/something')
def index():
return 'host prefix is %s%s' % (request.host_url, g.url_prefix)
app = Flask(__name__)
app.register_blueprint(bp, url_prefix='/new_ep', url_defaults={'url_prefix': 'new_ep'})
app.register_blueprint(bp, url_prefix='/old_ep', url_defaults={'url_prefix': 'old_ep'})

Flask blueprint doesn't work without prefix

Hi I have a Flask app structured in following way and I have problem with blueprints setup. Whatever I do, they only work with url_prefix set up. It works currently as /main/verify but as it is a small app I would love to have an endpoint like /verify. What's interesting I managed to make it work with / route, but for the same configuration it didn't work for the /verify. I am pretty clueless right now, I can live with it as it is, but I really wonder what am I doing wrong.
Here is the code:
__init__.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from config import config
db = SQLAlchemy()
def create_app(config_name):
app = Flask(__name__)
app.config.from_object(config[config_name])
config[config_name].init_app(app)
db.init_app(app)
from main import main
app.register_blueprint(main)
return app
main/__init__.py
from flask import Blueprint
main = Blueprint('main', __name__, url_prefix='/main')
from . import views
main/views.py
from flask import request, jsonify
from . import main
#main.route('/')
def index():
return "Hello world"
#main.route('/verify')
def verify():
url = request.args['url']
query = request.args['query']
return jsonify({ ... })
As I see you didn't register blueprint without prefix. If you need to register endpoints without prefix you must create a new instance of Blueprint
main = Blueprint('main', __name__, url_prefix='/main')
# main endpoints(with prefix /main)...
#main.route('/')
def index_main():
return "Hello world from /main/"
# routes without any prefix
default = Blueprint('default', __name__)
#default.route('/')
def index():
return "Hello world from /"
app = Flask(__name__)
app.register_blueprint(main)
app.register_blueprint(default)
Hope this helps.

Flask - Blueprint - Before First Request?

I'm trying to add a before_first_request functionality to a specific Blueprint of my Flask application. Below you can see that I have two Blueprints, public and admin.
I have tried this but had no success: https://stackoverflow.com/a/27401269/7077556
This only works for the the first request that is made to the application, any other request from other device and ip after that first one is not handled by this "custom" before_first_request.
I want to run a function just for the first request that a client makes to the public Blueprint.
How can I do this? Thanks in advance
This is the code that I'm using:
from flask import Flask, Blueprint
application = Flask(__name__)
# PUBLIC Blueprint
public = Blueprint('public', __name__, static_url_path='/public', static_folder='static', template_folder='templates')
# ADMIN Blueprint
admin = Blueprint('admin', __name__, static_url_path='/admin', static_folder='static', template_folder='templates')
# Before First Request To Public BP
from threading import Lock
public._before_request_lock = Lock()
public._got_first_request = False
#public.before_request
def init_public_bp():
if public._got_first_request:
return
else:
with public._before_request_lock:
public._got_first_request = True
print('THIS IS THE FIRST REQUEST!')
# Do more stuff here...
# PUBLIC ROUTE
#public.route("/")
def public_index():
return 'Hello World!'
# ADMIN ROUTE
#admin.route('/')
def admin_index():
return 'Admin Area!'
# Register PUBLIC Blueprint
application.register_blueprint(public)
# Register ADMIN Blueprint
application.register_blueprint(admin, url_prefix='/admin')
if __name__ == "__main__":
application.run(host='0.0.0.0')
before_request of the blueprint instance isn't a decorator. It's just an instance method that takes a function to be called before a request. You should use it in this manner:
from __future__ import print_function
from flask import Flask, Blueprint
application = Flask(__name__)
# PUBLIC Blueprint
public = Blueprint('public', __name__, static_url_path='/public', static_folder='static', template_folder='templates')
# ADMIN Blueprint
admin = Blueprint('admin', __name__, static_url_path='/admin', static_folder='static', template_folder='templates')
# Before First Request To Public BP
from threading import Lock
public._before_request_lock = Lock()
public._got_first_request = False
def init_public_bp():
if public._got_first_request:
return # or pass
with public._before_request_lock:
public._got_first_request = True
print('THIS IS THE FIRST REQUEST!')
# Do more stuff here...
public.before_request(init_public_bp)
# PUBLIC ROUTE
#public.route("/")
def public_index():
return 'Hello World!'
# ADMIN ROUTE
#admin.route('/')
def admin_index():
return 'Admin Area!'
# Register PUBLIC Blueprint
application.register_blueprint(public)
# Register ADMIN Blueprint
application.register_blueprint(admin, url_prefix='/admin')
if __name__ == "__main__":
application.run(host='0.0.0.0')

Flask, Blueprint, current_app

I am trying to add a function in the Jinja environment from a blueprint (a function that I will use into a template).
Main.py
app = Flask(__name__)
app.register_blueprint(heysyni)
MyBluePrint.py
heysyni = Blueprint('heysyni', __name__)
#heysyni.route('/heysyni'):
return render_template('heysyni.html', heysini=res_heysini)
Now in MyBluePrint.py, I would like to add something like :
def role_function():
return 'admin'
app.jinja_env.globals.update(role_function=role_function)
I will then be able to use this function in my template. I cannot figure out how I can access the application since
app = current_app._get_current_object()
returns the error:
working outside of request context
How can I implement such a pattern ?
The message error was actually pretty clear :
working outside of request context
In my blueprint, I was trying to get my application outside the 'request' function :
heysyni = Blueprint('heysyni', __name__)
app = current_app._get_current_object()
print(app)
#heysyni.route('/heysyni/')
def aheysyni():
return 'hello'
I simply had to move the current_app statement into the function. Finally it works that way :
Main.py
from flask import Flask
from Ablueprint import heysyni
app = Flask(__name__)
app.register_blueprint(heysyni)
#app.route("/")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run(debug=True)
Ablueprint.py
from flask import Blueprint, current_app
heysyni = Blueprint('heysyni', __name__)
#heysyni.route('/heysyni/')
def aheysyni():
# Got my app here
app = current_app._get_current_object()
return 'hello'

Categories

Resources