这不是 FastAPI 的问题,而是 Starlette's 的问题(即 request.url_for() 接收路径参数,不是查询参数)。因此,受#560 和#1385 的启发,我创建了以下工作示例,用于从 jinja2 模板中调用 FastAPI 路由,并传递 query 参数(单独或与 path em> 参数,以及)。
请注意,此功能可能即将引入下一版 Starlette #1385。因此,最好在它用完时使用它。
app.py
import uvicorn
from fastapi import FastAPI, Response
from fastapi.templating import Jinja2Templates
from fastapi import Request
from fastapi.responses import StreamingResponse, HTMLResponse
import urllib
app = FastAPI()
class CustomURLProcessor:
def __init__(self):
self.path = ""
self.request = None
def url_for(self, request: Request, name: str, **params: str):
self.path = request.url_for(name, **params)
self.request = request
return self
def include_query_params(self, **params: str):
parsed = list(urllib.parse.urlparse(self.path))
parsed[4] = urllib.parse.urlencode(params)
return urllib.parse.urlunparse(parsed)
templates = Jinja2Templates(directory='templates')
templates.env.globals['CustomURLProcessor'] = CustomURLProcessor
@app.get('/updates/page/{page_no}/item/{item_id}')
async def updates(request: Request, page_no: int, item_id: int, user: str, msg: str):
return templates.TemplateResponse("item.html", {"request": request, "page_no": page_no, "item_id":item_id, "user": user, "msg": msg})
@app.get('/updates_query_only')
async def updates_query_only(request: Request, user: str, msg: str):
return templates.TemplateResponse("item.html", {"request": request, "user": user, "msg": msg})
@app.get('/')
async def index(request: Request):
return templates.TemplateResponse("index.html", {"request": request})
if __name__ == '__main__':
uvicorn.run(app, host='127.0.0.1', port=8000, debug=True)
模板/index.html
<!DOCTYPE html>
<html>
<body>
<div class="container">
{% set cu = CustomURLProcessor() %}
{% set _url = cu.url_for(request, 'updates', page_no=5, item_id=3).include_query_params(user='foo', msg='bar') %}
<!-- if only query params required, use as follows: -->
{# {% set _url = cu.url_for(request, 'updates_query_only').include_query_params(user='foo', msg='bar') %} #}
<iframe src="{{ _url }}" width = 300 height = 300 style= "border: none;"></iframe>
</div>
</body>
</html>
模板/item.html
<!DOCTYPE html>
<html>
<body>
<h1>Page No {{ page_no }}</h1>
<h2>Item {{ item_id }}</h2>
<h3>{{ user }}</h3>
<h4>{{ msg }}</h4>
</body>
</html>