mod = Blueprint('users', __name__, url_prefix='/users')
#mod.route('/welcome')
def www():
return '<h1>Hello</h1>'
#mod.before_app_request
def before_request():
return redirect(url_for('www'))
This code give me this error:
raise BuildError(endpoint, values, method)
BuildError: ('www', {}, None)
If I try this one, I will get an infinite loop redirect in the browser.
return redirect(url_for('users.www'))
My question is, how can I redirect the before_app_request to another action?
EDIT: log after changes, Now the redirect works, but the error still exists.
http://sharetext.org/dDje
With the way you set this up pretty much every request for this blueprint, including one to 'users.www' - hence the infinite loop redirect. You need some kind of conditions so that it would learn not to redirect and load the /welcome endpoint.
Also, url_for('www') will not work as you intend as you need . prefix to reference the current blueprint. Check the documentation for url_for
Maybe something like:
#mod.before_app_request
def before_request():
if request.endpoint != 'users.www':
return redirect(url_for('.www'))
Do note that you might want to print out the request.endpoint and grab the exact one, I can't remember how they are flask handles/names them internally for blueprints.
Reference: flask before request - add exception for specific route
Related
I have a Flask web page that is using a library that do not load properly when the Flask decorator '#app.after_request' is used. Is there a way to disable that decorator only for certain pages?
You could make your own decorator function that checks for the request path or just check in another function.
#app.route('/whatever/path')
def check_func():
if request.path == "doesn't/work":
return view_func()
else:
return app.after_request(view_func)
I'm not sure if this is best practice.
You could add a condition in your #app.after_request decorator to exit it if the path in request is the one you want to exclude from decorator.
#app.after_request
def myAfterRequest():
if ( request.path == 'path/to/exclude' ):
return
#decorator code
return
Thank you so much for your replies. Just a side note (because it took me a while to figure out why :-)): For those that are also using 'request' from 'urllib' in addition to 'flask', the proposed solutions only works if you make aliases. This will work:
from flask import Flask, render_template, request
This will not work:
from urllib import request
from flask import Flask, render_template
I have a FastAPI app that worked fine until now. Here is the main router:
#router.get('/{inst_name}')
def chart(request: Request, inst_name: str):
# Initializing an instance of class 'LiveData'
lv = tse.LiveData(inst_name, 1)
data = lv.get_data_for_charts('1min')
return templates.TemplateResponse('chart.html',
{
'request': request,
'title': inst_name,
'data': data
})
Today I changed Javascript code that renders chart.html and tried to re-run the app. No matter how much I refreshed the page, I could not see the changes made. So, I decided to do a hard reload on the page, but I got a strange result. The router function was run twice ; the first one did everything as I expected, and the second one failed on the assertion check in the class initialization. Here is the __init__ method of the class:
def __init__(self, inst, avg_volume: int):
print('inst name:', inst)
self._inst_name = inst
inst_id = AllInstCodes().get_inst_id_by_name(inst)
assert inst_id is not None, 'Invalid instrument name.'
I put a print statement inside above method to see what causes the assertion to fail. The inst parameter in the second initialization of the class is favicon.ico !!!
Why the router method runs twice and where does favicon.ico come from?
The GET /favicon.ico request is a request your browser makes to retrieve the site's icon that gets shown on the tab in your browser (or in your bookmarks, etc.)
You can ignore this error; it's a request your browser makes in the background and unless you do something very specific with it (i.e. change internal state, etc.) it shouldn't affect anything. You can create an explicit endpoint for it if you want to handle it properly and return a 404 error instead.
The reason why the endpoint runs twice is that there are two requests - your own and the browser's request for favicon.ico.
Most common REST API designs uses the resource group name as the initial part of the path to avoid conflicts with other groups that gets added later, so you'd have:
#router.get('/instruments/{inst_name}')
instead. This will automagically give a 404 error when anyone attempts to request an undefined path.
I'm working on a Flask app that needs user management. However, I have multiple parts of my site, let's call them /site/<name>/ with each of them having their own users (linked in the DB to name).
So, what I want to achieve is:
Any unauthorised access to anything /site/<name>/<path> gets redirected to /site/<name>/login (so, I cannot simply redefine login_view_function).
When the user logs in, the argument name is also used (so, a user from /site/name1/ cannot log in at /site/name2/).
A login from /site/name1/login works inside /site/name1/<path>, but not in /site/name2/<path> (the user is unauthorised there; can also get logged out of name1... I don't particularly care what exactly happens).
Whatever happens outside of /site/<name>/ (or for invalid name) is irrelevant for now.
I tried redefining URL rules in a before_request decorated function:
site_manager = UserManager(db_adapter, app)
...
#app.before_request
def config_flask_user():
m = re.match(r'https?://[^/]+/site/(?P<name>[^:/]*)', request.url)
if m:
name = m.group('name')
flask.g.app_theme = name
if not name_ok(name):
flask.abort(404)
# Make a no-arguments node for the current site
app.debug = False
app.add_url_rule(
'/site/%s/' % name,
'site.current',
site,
methods=['GET', 'POST'],
defaults={'name': name},
)
app.debug = DEBUG
# Use it as the post-logout endpoint, so that it leads to a page
# where re-login works properly
site_manager.after_logout_endpoint = 'site.current'
# Override existing `login_url` and `logout_url` routes, to fit
# the current site path
for action in ('login', 'logout'):
rule = '/site/%s/%s/' % (name, action)
endpoint = getattr(site_manager, action + "_url")
view_func = getattr(site_manager, action + "_view_function")
for r in app.url_map._rules:
if r.rule == endpoint:
print("Redefining rule", endpoint, "as", rule)
r.rule = rule
r.refresh()
This seemed to work fine, but it actually breaks if the server is restarted between loading the Login page and actually submitting user's login and password, seemingly due to that spot being too late to redefine these paths, and I'm worried that it's the wrong approach (maybe it can cause collisions between different requests to different "sites"?), especially for the intended multi-worker environment.
TL;DR: How to get /site/<name>/ paths to have Flask-User login dependent on the name argument?
I have a helper method in a Flask app that is used by several endpoints to get a resource. To avoid having multiple redirect_url calls everywhere, I want to be able to redirect from just this helper method. Throwing a RequestRedirect exception as shown here correctly returns a 301 response, but doesn't set the Content-Location error. To get around this, I added a after_this_request hook that sets the url for that response.
This seems to work correctly, but I was wondering if theres a more elegant way to go about it.
Anonymized helper method:
def get_resource(resource_id):
try:
# Some logic
except:
#after_this_request
def add_header(response):
response.headers['Content-Location'] = url
return response
raise RequestRedirect(new_url='/')
If it is outside of your api, typically you would redirect to a 404 page. Here's a sample:
#app.errorhandler(404)
def page_not_found(e):
return render_template('404.html'), 404
Flask introduced the following change in 0.10:
Flask will now raise an error if you attempt to register a new function on an already used endpoint.
I've used the following code on my home page:
# ...
# ...
# some endpoints registered there
#theApp.route("/<path:filename>")
def static(filename):
if (os.path.isfile("templates/" + filename)):
return render_template(filename)
elif (os.path.isfile("static/" + filename)):
return theApp.send_static_file(filename)
else:
return (render_template("404.html"), 404)
This handler is used to handle everything that exists, no matter static or template.
Now this gives me an exception during startup.
How I can avoid an exception without registering too detailed handlers?
If you dont pass endpoint to route, by default the endpoint is the decorated function name. Flask already has a static endpoint, used for serving files from your static dir. Renaming the function or passing endpoint='mystatic' to the route decorator should fix it.
URL Route Registrations