Cast a dynamic Flask URL route path to string - python

I have a catch-all route set up in Flask and I want to parse the URL regardless of the length.
from flask import Flask
app = Flask(__name__)
app.route('/')
app.route('/<path:path>')
def main(path=None):
if path == None:
return 'foo'
else:
return 'bar'
if __name__ == '__main__':
app.run()
The problem is I'm getting a 404 Not Found error and I don't know why. The url I'm using to test is /hello/world/. Thanks in advance.

You forgot # before routing decorators. Change it this way:
#app.route('/')
#app.route('/<path:path>')
and it will work.

Related

(Beginner) Flask dynamic routing not working

I'm just starting to learn Flask but I can't even get through this beginner step. I have tried to make a dynamic URL route as below but when I go to http://127.0.0.1:5000/home for example, it says "NOT FOUND". Any help appreciated!
from flask import Flask
app = Flask(__name__)
#app.route("/") #this is the default domain
def home():
return "<h1>Hello this main page</h1>"
#app.route("/<name>")
def user(name):
return f"hi {name}"
if __name__ == "__main__":
app.run()
You forgot to set the route /home.
Try this :)
#app.route("/home")
def home():
return "<h1>Hello this main page</h1>"

Flask and React routing

I'm building the Flask app with React, I ended up having a problem with routing.
The backend is responsible to be an API, hence some routes look like:
#app.route('/api/v1/do-something/', methods=["GET"])
def do_something():
return something()
and the main route which leads to the React:
#app.route('/')
def index():
return render_template('index.html')
I'm using react-router in the React app, everything works fine, react-router takes me to /something and I get the rendered view, but when I refresh the page on /something then Flask app takes care of this call and I get Not Found error.
What is the best solution? I was thinking about redirecting all calls which are not calling /api/v1/... to / it's not ideal as I will get back the home page of my app, not rendered React view.
We used catch-all URLs for this.
from flask import Flask
app = Flask(__name__)
#app.route('/', defaults={'path': ''})
#app.route('/<path:path>')
def catch_all(path):
return 'You want path: %s' % path
if __name__ == '__main__':
app.run()
You can also go an extra mile and reuse the Flask routing system to match path to the same routes as client so you can embed the data client will need as JSON inside the HTML response.
Maybe as extension to the answers before. This solved the problem for me:
from flask import send_from_directory
#app.route('/', defaults={'path': ''})
#app.route('/<path:path>')
def serve(path):
path_dir = os.path.abspath("../build") #path react build
if path != "" and os.path.exists(os.path.join(path_dir, path)):
return send_from_directory(os.path.join(path_dir), path)
else:
return send_from_directory(os.path.join(path_dir),'index.html')
For some reason, the catch-all URLs did not work for me. I found that using the flask 404 handler results in the exact same thing. It sees the url and passes it down to react where your router will handle it.
#app.errorhandler(404)
def not_found(e):
return app.send_static_file('index.html')
Just to inform handle error 404 and render_template works perfectly for me.
#app.errorhandler(404)
def not_found(e):
return render_template("index.html")
I have to combine both catch-all and 404 handler for it to work properly. I am hosting a react-app in a subpath with its own redirection handler from react-router.
#app.route('/sub-path', defaults={'path': 'index.html'})
#app.route('/sub-path/<path:path>')
def index(path):
return send_from_directory('../react-dir/build', path)
#app.errorhandler(404)
def not_found(e):
return send_from_directory('../react-dir/build','index.html')

Blueprint 404 errorhandler doesn't activate under blueprint's url prefix

I created a blueprint with a 404 error handler. However, when I go to non-existent urls under the blueprint's prefix, the standard 404 page is shown rather than my custom one. How can I make the blueprint handle 404 errors correctly?
The following is a short app that demonstrates the problem. Navigating to http://localhost:5000/simple/asdf will not show the blueprint's error page.
#!/usr/local/bin/python
# coding: utf-8
from flask import *
from config import PORT, HOST, DEBUG
simplepage = Blueprint('simple', __name__, url_prefix='/simple')
#simplepage.route('/')
def simple_root():
return 'This simple page'
#simplepage.errorhandler(404)
def error_simple(err):
return 'This simple error 404', err
app = Flask(__name__)
app.config.from_pyfile('config.py')
app.register_blueprint(simplepage)
#app.route('/', methods=['GET'])
def api_get():
return render_template('index.html')
if __name__ == '__main__':
app.run(host=HOST,
port=PORT,
debug=DEBUG)
The documentation mentions that 404 error handlers will not behave as expected on blueprints. The app handles routing and raises a 404 before the request gets to the blueprint. The 404 handler will still activate for abort(404) because that is happening after routing at the blueprint level.
This is something that could possibly be fixed in Flask (there's an open issue about it). As a workaround, you can do your own error routing within the top-level 404 handler.
from flask import request, render_template
#app.errorhandler(404)
def handle_404(e):
path = request.path
# go through each blueprint to find the prefix that matches the path
# can't use request.blueprint since the routing didn't match anything
for bp_name, bp in app.blueprints.items():
if path.startswith(bp.url_prefix):
# get the 404 handler registered by the blueprint
handler = app.error_handler_spec.get(bp_name, {}).get(404)
if handler is not None:
# if a handler was found, return it's response
return handler(e)
# return a default response
return render_template('404.html'), 404

flask-restful having a get/<id> and post with json in the same class

The get method on user works if the # api.add_resource(User, '/user/')
line is uncommented, and the other api.add_resource is.
The inverse of that is true to make the post method work.
How can I get both of these paths to work?
from flask import Flask, request
from flask.ext.restful import reqparse, abort, Api, Resource
import os
# set the project root directory as the static folder, you can set others.
app = Flask(__name__)
api = Api(app)
class User(Resource):
def get(self, userid):
print type(userid)
if(userid == '1'):
return {'id':1, 'name':'foo'}
else:
abort(404, message="user not found")
def post(self):
# should just return the json that was posted to it
return request.get_json(force=True)
api.add_resource(User, '/user/')
# api.add_resource(User, '/user/<string:userid>')
if __name__ == "__main__":
app.run(debug=True)
Flask-Restful supports registering multiple URLs for a single resource. Simply provide both URLs when you register the User resource:
api.add_resource(User, '/user/', '/user/<userid>')

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