Mip*_*ips 5 python jinja2 fastapi
我想从 Jinja2 模板中调用 FastAPI 路由,并将路径和查询数据(参数)传递给该路由。我在 Jinja2 模板中尝试过如下所示:
{{ url_for('function1', uustr=data.uustr, interval=1) }}
Run Code Online (Sandbox Code Playgroud)
这是我想要调用的 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>
"""
Run Code Online (Sandbox Code Playgroud)
我收到此错误:
raise ValueError('context must include a "request" key')
ValueError: context must include a "request" key
Run Code Online (Sandbox Code Playgroud)
有人有想法吗?
这不是FastAPI的问题,而是Starlette的问题(即request.url_for()接收path参数,而不是 query参数)。因此,受#560和#1385的启发,我创建了以下工作示例,用于从 Jinja2 模板中调用 FastAPI 路由,并传递query参数(单独或与path参数一起传递)。
请注意,这个功能可能会被引入到 Starlette #1385的下一版本中。因此,最好在它出来时使用它。
应用程序.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)
Run Code Online (Sandbox Code Playgroud)
模板/index.html
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)
Run Code Online (Sandbox Code Playgroud)
模板/ item.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>
Run Code Online (Sandbox Code Playgroud)
您现在可以使用 Starlette 的starlette.datastructures.URL,它提供了一种方法include_query_params。下面的例子:
在app.py中导入该类URL并使其可从 Jinja2 模板访问:
<!DOCTYPE html>
<html>
<body>
<h1>Page No {{ page_no }}</h1>
<h2>Item {{ item_id }}</h2>
<h3>{{ user }}</h3>
<h4>{{ msg }}</h4>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
在 templates/ item.html中使用如下:
from starlette.datastructures import URL
templates = Jinja2Templates(directory="templates")
templates.env.globals['URL'] = URL
Run Code Online (Sandbox Code Playgroud)
该request.url_for()函数现在返回一个starlette.datastructures.URL对象。因此,您可以简单地将查询参数添加到 URL,如下所示:
<!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>
Run Code Online (Sandbox Code Playgroud)
Mip*_*ips -1
我找到了一个非常简单的解决方案,无需使用url_for()
如果来自 Flask 世界的人在这里遇到类似的问题,我的解决方案是:我在 jinja2 模板中创建了一个简单的 HTML 按钮:
<button onclick="myFunction()">pass data to route</button>
Run Code Online (Sandbox Code Playgroud)
我创建了一个非常简单的 JavaScript 函数来将数据传递给路由:
<script>
function myFunction() {
window.location.href = "/updates/data/{{data.uustr}}?interval=2";
}
</script>
Run Code Online (Sandbox Code Playgroud)
就是这样。
| 归档时间: |
|
| 查看次数: |
5265 次 |
| 最近记录: |