FastAPI:从视图名称(路由名称)中检索 URL
FastAPI: Retrieve URL from view name ( route name )
假设我有以下观点,
from fastapi import FastAPI
app = FastAPI()
@app.get('/hello/')
def hello_world():
return {"msg": "Hello World"}
@app.get('/hello/{number}/')
def hello_world_number(number: int):
return {"msg": "Hello World Number", "number": number}
我一直在 Flask 和 Django 中使用这些函数
那么,我如何才能以类似的方式 obtain/build hello_world
和 hello_world_number
的 URL?
我们有Router.url_path_for(...)
method which is located inside the starlette包
方法一:使用FastAPI
实例
当您能够在当前上下文中访问 FastAPI
实例时,此方法很有用。 (感谢 @Yagizcan Degirmenci)
from fastapi import FastAPI
app = FastAPI()
@app.get('/hello/')
def hello_world():
return {"msg": "Hello World"}
@app.get('/hello/{number}/')
def hello_world_number(number: int):
return {"msg": "Hello World Number", "number": number}
print(app.url_path_for('hello_world'))
print(app.url_path_for('hello_world_number', number=1))
print(app.url_path_for('hello_world_number', number=2))
# Results
"/hello/"
"/hello/1/"
"/hello/2/"
缺点
- 如果我们使用
APIRouter
,router.url_path_for('hello_world')
可能无法工作,因为 router
不是不是 FastAPI
class 的实例。也就是说,我们必须有 FastAPI
实例来解析 URL
方法二:Request
实例
当您能够访问 Request
实例(传入请求)时,此方法很有用,通常是在视图中。
from fastapi import FastAPI, Request
app = FastAPI()
@app.get('/hello/')
def hello_world():
return {"msg": "Hello World"}
@app.get('/hello/{number}/')
def hello_world_number(number: int):
return {"msg": "Hello World Number", "number": number}
@app.get('/')
def named_url_reveres(request: Request):
return {
"URL for 'hello_world'": request.url_for("hello_world"),
"URL for 'hello_world_number' with number '1'": request.url_for("hello_world_number", number=1),
"URL for 'hello_world_number' with number '2''": request.url_for("hello_world_number", number=2})
}
# Result Response
{
"URL for 'hello_world'": "http://0.0.0.0:6022/hello/",
"URL for 'hello_world_number' with number '1'": "http://0.0.0.0:6022/hello/1/",
"URL for 'hello_world_number' with number '2''": "http://0.0.0.0:6022/hello/2/"
}
缺点
- 我们必须在每个(或必需的)视图中包含
request
参数来解决 URL,这可能会给开发人员带来 丑陋 的感觉。
url_for 存在,但由支持 FastApi 的服务器 starlette 提供:
https://www.starlette.io/routing/#reverse-url-lookups
其实你不需要重新发明轮子。 FastAPI 支持此 out-of-box (实际上是 Starlette),并且效果很好。
app = FastAPI()
@app.get("/hello/{number}/")
def hello_world_number(number: int):
return {"msg": "Hello World Number", "number": number}
如果你有这样的端点,你可以简单地使用
In: app.url_path_for("hello_world_number", number=3)
In: app.url_path_for("hello_world_number", number=50)
Out: /hello/3/
Out: /hello/50/
在FastAPI中,APIRouter和FastAPI(APIRoute)继承自Router(Starlette's) 所以,如果你有这样的 APIRouter,你可以继续使用这个功能
router = APIRouter()
@router.get("/hello")
def hello_world():
return {"msg": "Hello World"}
In: router.url_path_for("hello_world")
Out: /hello
如果在多个APIRouter下定义了相同的函数名,request.url_for
和router.url_path_for
将return第一个匹配的函数名(按照include_router的顺序)。
这里有一个在函数名冲突时用APIRouter的tag获取正确url的方法,如果有人需要的话:
第 1 步: 将其放入您的 __init__.py
:
def url_of(request: Request, name: str, **path_params: dict):
from fastapi.routing import APIRoute
from starlette.routing import NoMatchFound
tag, tid, fname = None, name.find('.'), name
if tid > 0:
tag = name[:tid]
fname = name[tid + 1:]
url_no_tag = None
for route in request.app.router.routes:
if not isinstance(route, APIRoute):
continue
if fname == route.name and (not tag or tag in route.tags):
try:
url_path = route.url_path_for(fname, **path_params)
url_no_tag = url_path.make_absolute_url(base_url=request.base_url)
if tag:
return url_no_tag
except NoMatchFound:
pass
if url_no_tag:
return url_no_tag
return request.url_for(name, **path_params)
步骤 2: 为 APIRouters 添加标签:
router = APIRouter(prefix='/user', tags=['user'])
@router.get('/')
def login():
return 'login page'
第 3 步: 在任意位置检索 url:
@router2.get('/test')
def test(request: Request):
return RedirectResponse(url_of(request, 'user.login') + '?a=1')
2021/07/10 将 url_as
重命名为 url_of
如果您需要解析模板中的 URL,Starlette(所以 FastAPI)定义了
url_for()
在默认 Jinja 环境中使用 request
函数
上下文实例和 url_for
方法:
https://github.com/encode/starlette/blob/master/starlette/templating.py#L63
要在模板中使用它:{{ url_for('hello_world_number', number=42) }}
。
假设我有以下观点,
from fastapi import FastAPI
app = FastAPI()
@app.get('/hello/')
def hello_world():
return {"msg": "Hello World"}
@app.get('/hello/{number}/')
def hello_world_number(number: int):
return {"msg": "Hello World Number", "number": number}
我一直在 Flask 和 Django 中使用这些函数
那么,我如何才能以类似的方式 obtain/build hello_world
和 hello_world_number
的 URL?
我们有Router.url_path_for(...)
method which is located inside the starlette包
方法一:使用FastAPI
实例
当您能够在当前上下文中访问 FastAPI
实例时,此方法很有用。 (感谢 @Yagizcan Degirmenci)
from fastapi import FastAPI
app = FastAPI()
@app.get('/hello/')
def hello_world():
return {"msg": "Hello World"}
@app.get('/hello/{number}/')
def hello_world_number(number: int):
return {"msg": "Hello World Number", "number": number}
print(app.url_path_for('hello_world'))
print(app.url_path_for('hello_world_number', number=1))
print(app.url_path_for('hello_world_number', number=2))
# Results
"/hello/"
"/hello/1/"
"/hello/2/"
缺点
- 如果我们使用
APIRouter
,router.url_path_for('hello_world')
可能无法工作,因为router
不是不是FastAPI
class 的实例。也就是说,我们必须有FastAPI
实例来解析 URL
方法二:Request
实例
当您能够访问 Request
实例(传入请求)时,此方法很有用,通常是在视图中。
from fastapi import FastAPI, Request
app = FastAPI()
@app.get('/hello/')
def hello_world():
return {"msg": "Hello World"}
@app.get('/hello/{number}/')
def hello_world_number(number: int):
return {"msg": "Hello World Number", "number": number}
@app.get('/')
def named_url_reveres(request: Request):
return {
"URL for 'hello_world'": request.url_for("hello_world"),
"URL for 'hello_world_number' with number '1'": request.url_for("hello_world_number", number=1),
"URL for 'hello_world_number' with number '2''": request.url_for("hello_world_number", number=2})
}
# Result Response
{
"URL for 'hello_world'": "http://0.0.0.0:6022/hello/",
"URL for 'hello_world_number' with number '1'": "http://0.0.0.0:6022/hello/1/",
"URL for 'hello_world_number' with number '2''": "http://0.0.0.0:6022/hello/2/"
}
缺点
- 我们必须在每个(或必需的)视图中包含
request
参数来解决 URL,这可能会给开发人员带来 丑陋 的感觉。
url_for 存在,但由支持 FastApi 的服务器 starlette 提供: https://www.starlette.io/routing/#reverse-url-lookups
其实你不需要重新发明轮子。 FastAPI 支持此 out-of-box (实际上是 Starlette),并且效果很好。
app = FastAPI()
@app.get("/hello/{number}/")
def hello_world_number(number: int):
return {"msg": "Hello World Number", "number": number}
如果你有这样的端点,你可以简单地使用
In: app.url_path_for("hello_world_number", number=3)
In: app.url_path_for("hello_world_number", number=50)
Out: /hello/3/
Out: /hello/50/
在FastAPI中,APIRouter和FastAPI(APIRoute)继承自Router(Starlette's) 所以,如果你有这样的 APIRouter,你可以继续使用这个功能
router = APIRouter()
@router.get("/hello")
def hello_world():
return {"msg": "Hello World"}
In: router.url_path_for("hello_world")
Out: /hello
如果在多个APIRouter下定义了相同的函数名,request.url_for
和router.url_path_for
将return第一个匹配的函数名(按照include_router的顺序)。
这里有一个在函数名冲突时用APIRouter的tag获取正确url的方法,如果有人需要的话:
第 1 步: 将其放入您的 __init__.py
:
def url_of(request: Request, name: str, **path_params: dict):
from fastapi.routing import APIRoute
from starlette.routing import NoMatchFound
tag, tid, fname = None, name.find('.'), name
if tid > 0:
tag = name[:tid]
fname = name[tid + 1:]
url_no_tag = None
for route in request.app.router.routes:
if not isinstance(route, APIRoute):
continue
if fname == route.name and (not tag or tag in route.tags):
try:
url_path = route.url_path_for(fname, **path_params)
url_no_tag = url_path.make_absolute_url(base_url=request.base_url)
if tag:
return url_no_tag
except NoMatchFound:
pass
if url_no_tag:
return url_no_tag
return request.url_for(name, **path_params)
步骤 2: 为 APIRouters 添加标签:
router = APIRouter(prefix='/user', tags=['user'])
@router.get('/')
def login():
return 'login page'
第 3 步: 在任意位置检索 url:
@router2.get('/test')
def test(request: Request):
return RedirectResponse(url_of(request, 'user.login') + '?a=1')
2021/07/10 将 url_as
重命名为 url_of
如果您需要解析模板中的 URL,Starlette(所以 FastAPI)定义了
url_for()
在默认 Jinja 环境中使用 request
函数
上下文实例和 url_for
方法:
https://github.com/encode/starlette/blob/master/starlette/templating.py#L63
要在模板中使用它:{{ url_for('hello_world_number', number=42) }}
。