从 Jinja 模板发送查询参数

问题描述 投票:0回答:1

我不知道是否可以将查询参数从静态 html 页面传递到视图进行处理。我现在已经使用路径参数实现了我需要的功能。我想做同样的事情,但是带有查询参数

main.py

from helpers.utils import CustomURLProcessor

app = FastAPI()

app.mount("/static", StaticFiles(directory="static"), name="static")
templates = Jinja2Templates(directory="templates")
templates.env.globals['CustomURLProcessor'] = CustomURLProcessor

事件.py

router = APIRouter()
templates = Jinja2Templates(directory="templates")

@router.post('/invite/{event_invite}/sender/{sender}')
async def decline_event_invite(
        request: Request,
        event_invite: int,
        sender: int,
):
    #logic

routes.py

api_router.include_router(events.router, prefix="/event")

html

{{ url_for('decline_event_invite',  event_invite=invite.id, sender=invite.sender) }}

它可以与

"POST /event/invite/15/sender/3 HTTP/1.1"
作为示例

尝试使用查询参数

@router.post('/invite')
async def decline_event_invite(
        request: Request,
        event_invite: Optional[str] = None,
        sender: Optional[str] = None,
):
    # logic

并得到

    raise NoMatchFound()
starlette.routing.NoMatchFound

html模板没有任何改变

我可以将查询参数从模板传递到fastapi逻辑来处理这个url吗

/event/?event_invite=15&sender=3

python jinja2 fastapi starlette
1个回答
4
投票

这是Starlette 的问题(即

url_for()
接收
path
参数,不是
query
参数)。您可以做的是创建一个自定义 URL 处理器(如下所示)并使用它来传递
path
和/或
query
参数。

import urllib

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)

记住将

CustomURLProcessor
类添加到模板的全局环境中:

templates.env.globals['CustomURLProcessor'] = CustomURLProcessor

然后在Jinja模板中使用,如下:

{{ CustomURLProcessor().url_for(request, 'decline_event_invite').include_query_params(event_invite=invite.id, sender=invite.sender) }}

请查看此答案以获取完整的工作示例。此外,该功能可能会被引入到 Starlette 的下一版本#1385中。因此,您可能需要密切关注。

有关如何从 Jinja 模板访问类的更多选项

使

CustomURLProcessor
类可从 Jinja 模板访问的替代选项,以防
templates.env.globals['CustomURLProcessor'] = CustomURLProcessor
不适合您,并抛出以下错误:
jinja2.exceptions.UndefinedError: 'CustomURLProcessor' is undefined

选项1

templates.env.globals.update(CustomURLProcessor=CustomURLProcessor)

选项2

import helpers.utils
templates.env.globals['CustomURLProcessor'] = helpers.utils.CustomURLProcessor
# or, equivalently 
templates.env.globals.update(CustomURLProcessor=helpers.utils.CustomURLProcessor)

您甚至可以添加整个模块,并在 Jinja 模板中使用,如下所示

helpers.CustomURLProcessor().url_for(request...

import helpers.utils
templates.env.globals['helpers'] = helpers.utils

选项3

最后一个选项是将其作为您的

TemplateResponse
的一部分传递。

return templates.TemplateResponse("index.html",  {"request": request, "CustomURLProcessor": CustomURLProcessor})

如果上述方法均不起作用,也许此处描述的其他选项可能会有所帮助,或者问题可能出在其他地方。

更新 1 - 关于包含查询参数

关于从 Jinja 模板发送查询参数,您现在可以使用 Starlette 的

starlette.datastructures.URL
,它提供了
include_query_params
方法。

要使用,请导入

URL
类并使其可从 Jinja2 模板访问:

from starlette.datastructures import URL

templates = Jinja2Templates(directory="templates")
templates.env.globals['URL'] = URL

然后,在 Jinja 模板中使用,如下所示:

{{ URL(url_for('decline_event_invite')).include_query_params(event_invite=invite.id, sender=invite.sender) }}

更新 2 - 关于包含查询参数

request.url_for()
函数现在返回一个
starlette.datastructures.URL
对象。因此,您可以简单地使用以下内容,而不需要在 Jinja2 模板中导入
URL
类:

{{ url_for('decline_event_invite').include_query_params(event_invite=invite.id, sender=invite.sender) }}

© www.soinside.com 2019 - 2024. All rights reserved.