In the Flask framework, I would like to be able to determine which request route would be selected to serve a URL, without having to actually request the URL itself. For example, if I have an app like:
import flask
app = flask.Flask(__name__)
@app.route('/')
def index():
pass
@app.route('/<id:int>')
@app.route('/<id:int>-<slug>')
def show_page(id, slug = None):
pass
then I'd like to be able to do something like (fictional example):
route = app.get_url_rule("/12345")
and get a result like:
('show_page', {'id':12345,'slug':None})
As far as I can tell, Flask doesn't expose any functionality like this on its own, but is there a way to possibly dig down into its request routing layer (or possibly Werkzeug) to implement this myself?
CodePudding user response:
I tried Davidism's method with your route code, in case this helps...
from flask import Flask, request
app = Flask(__name__)
@app.route('/<int:id>')
@app.route('/<int:id>-<slug>')
def show_page(id, slug = None):
adapter = app.create_url_adapter(request)
endpoint, values = adapter.match()
# Return this to frontend of ease of demo
return {endpoint: values}
A request to /123
returns:
{
"show_page": {
"id": 123
}
}
A request to /123-abc
returns:
{
"show_page": {
"id": 123,
"slug": "abc"
}
}
CodePudding user response:
The result you're looking for is exactly what Flask does for routing, through Werkzeug. When you decorate view functions, the rules are registered in an instance of werkzeug.routing.Map
. When the app handles a request, the map is bound to the request to create a MapAdapter
. The adapter has a match()
method which either returns an endpoint, args
match or raises a routing error such as 307, 404, or 405. Flask call this and uses the result to call the appropriate view function.
Call app.create_url_adapter()
to get an adapter based on the app configuration. When not in a request, this requires configuring SERVER_NAME
. Then call adapter.match(url)
to get a match. This example ignores routing exceptions and returns None.
from werkzeug.exceptions import HTTPException
# remember to configure app.config["SERVER_NAME"]
def match_url(url):
adapter = app.get_url_adapter()
try:
return adapter.match(url)
except HTTPException:
return None
Calling match_url("/12345-example")
returns ('show_page', {'id': 12345, 'slug': 'example'})
.
Note that this normally isn't useful, as the point of Flask is that it will already do the routing and call the appropriate view.