首页 > 解决方案 > Python FastAPI:来自 Jinja2 模板的不同数量的输入项

问题描述

我正在尝试使用Jinja2和为我的 API 构建一个简单的 Web 界面 (UI) FastAPI。UI 的一部分(包括两个输入)是固定的,但另一部分是通过HTML使用字典中的键/项目填充模板来动态创建的。为简单起见,我使用的字典只有 3 个键/项,但实际上可能有 8 个或 11 个键和项。我正在努力收集动态生成的输入,因为我不确定如何做到这一点,而不必在代码中硬编码它们的名称。下面是函数中硬编码参数的示例。有什么方法可以一次收集所有输入,然后以某种方式“解包”它们?我考虑将输入放在可编辑的表格中,但后来我再次努力收集表格的内容。

这是用户界面:

在此处输入图像描述

这是Python代码:

from fastapi import FastAPI, Request, Form
from fastapi.templating import Jinja2Templates

dct = {"ctp_a": 1,
       "ctp_b": 2,
       "ctp_c": 20}

app = FastAPI()
templates = Jinja2Templates(directory="templates/")

@app.get("/form")
def form_post(request: Request):
    result = dct
    return templates.TemplateResponse('form3.html', context={'request': request, 'result': result})

@app.post("/form")
def form_post(
        request: Request, multiply_by: int = Form(...),
        # this is hardcoded which I don't like
        ctp_a_nm: str = Form(...), ctp_b_nm: str = Form(...), ctp_c_nm: str = Form(...),
        # this is hardcoded as well
        ctp_a: int = Form(...), ctp_b: int = Form(...), ctp_c: int = Form(...)
        ):
    
    result = {ctp_a_nm: ctp_a*multiply_by,
              ctp_b_nm: ctp_b*multiply_by,
              ctp_c_nm: ctp_c*multiply_by}
    
    return templates.TemplateResponse('form3.html', context={'request': request, 'result': result})

这是html模板。

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Sample Form</title>
    </head>
    <body>
        <form method="post">
            
            <label for="multiply_by">Multiply by</label><br>
            <input type="number" name="multiply_by" value="2"/><br><br>

            {% for key in result %}
                <input type="text" name="{{ key }}_nm" value="{{ key }}" readonly />
                <input type="number" name="{{ key }}" value="{{ result[key] }}"/><br>
            {% endfor %}
            
            <br><input type="submit">
            
        </form>
    </body>
</html>

标签: pythonjinja2fastapi

解决方案


这个答案建立在@MatsLindh 在评论中建议的基础上。

POST 请求部分可以像这样重写,允许 n 个键/值。

@app.post("/form")
def form_post(
        request: Request,
        multiply_by: int = Form(...),
        name: List[str] = Form(...),
        key: List[int] = Form(...),
        ):
    
    result = dict(zip(name, [k*multiply_by for k in key]))

    return templates.TemplateResponse('form3.html', context={'request': request, 'result': result})

需要更改 UI 以引用具有唯一名称的名称和值。

    {% for key in result %}
        <input type="text" name="name" value="{{ key }}" readonly />
        <input type="number" name="key" value="{{ result[key] }}"/><br>
    {% endfor %}

推荐阅读