如何使用url_for()传递路径和查询数据到使用FastAPI和Jinja2的路由?



我想从Jinja2模板中调用FastAPI路由,并将路径查询数据(参数)传递给该路由。我在Jinja2模板中尝试了这样的东西:

{{ url_for('function1', uustr=data.uustr, interval=1) }}

下面是我想调用的FastAPI路由(为了演示的目的,语法已经简化了):

@app.get("/updates/data/{uustr}",response_class=HTMLResponse)
async def function1(request: Request, uustr:str, interval:int):
return"""
<html>
<head>
<title>{{ uustr }}</title>
</head>
<body>
<h1>{{ interval }}</h1>
</body>
</html>
"""

我得到这个错误:

raise ValueError('context must include a "request" key') 
ValueError: context must include a "request" key

有谁有主意吗?

这不是FastAPI的问题,而是Starlette的问题(即,request.url_for()接收path参数,而不是)query参数)。因此,受到#560和#1385的启发,我创建了以下工作示例,用于从Jinja2模板中调用FastAPI路由,并传递query参数(单独或与path参数一起)。

请注意,这是一个可能即将被引入星列#1385的下一个版本的功能。因此,当它不在时,最好使用它。

app.py

import uvicorn
from fastapi import FastAPI, Response
from fastapi.templating import Jinja2Templates
from fastapi import Request
from fastapi.responses import 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}')
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')
def updates_query_only(request: Request, user: str, msg: str):
return templates.TemplateResponse("item.html", {"request": request, "user": user, "msg": msg})
@app.get('/')
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>
<标题>

更新你现在可以使用Starlette的starlette.datastructures.URL,它为include_query_params提供了一个方法。在下面的例子:

在<<p> strong> app.py 导入URL类,并使其可从Jinja2模板访问:
from starlette.datastructures import URL
templates = Jinja2Templates(directory="templates")
templates.env.globals['URL'] = URL

在模板/item.html使用方法如下:

<!DOCTYPE html>
<html>
<body>
<div class="container">
<iframe src="{{ URL(url_for('updates', page_no=5, item_id=3)).include_query_params(user='foo', msg='bar') }}" width = 300 height = 300 style= "border: none;"></iframe>
</div>
</body>
</html>

我发现了一个非常简单的解决方案,不使用url_for()

如果有人来自flask世界有类似的问题在这里我的解决方案:我在jinja2模板中创建了一个简单的HTML按钮:

<button onclick="myFunction()">pass data to route</button>

和我创建了一个非常简单的javascript函数来传递数据到路由:

<script>
function myFunction() {
window.location.href = "/updates/data/{{data.uustr}}?interval=2";
}
</script>

最新更新