fastapi:wtforms库的应用
一,官方站
库地址:
https://pypi.org/project/WTForms/
代码站:
https://github.com/pallets-eco/wtforms/
文档:
https://wtforms.readthedocs.io/en/3.2.x/
二,代码:
python
router = APIRouter(prefix="/test", tags=["测试"])
# 1. 定义 WTForms 表单类
class DemoForm(WTForm):
# Select 元素:下拉选择框
# choices 接收一个由 (值, 显示文本) 组成的元组列表
city = SelectField(
"选择城市",
choices=[(0, "北京"), (1, "上海"), (2, "广州")], default=0,
validators=[DataRequired(message="请选择一个城市")],
)
# Radio 元素:单选框
gender = RadioField(
"性别",
choices=[(1, "男"), (0, "女")],default=1,
validators=[DataRequired(message="请选择性别")],
)
# Textarea 元素:多行文本输入框
bio = TextAreaField(
"个人简介", validators=[DataRequired(message="请输入个人简介")]
)
# 2. GET 路由:渲染包含空表单的页面
@router.api_route("/demo", methods=["GET", "POST"], response_class=HTMLResponse)
async def show_form(request: Request):
if request.method == "GET":
form = DemoForm()
return templates.TemplateResponse(
request=request,
name="test/demo.html",
context={
"request": request, "form": form, "title": "登录"
}
)
elif request.method == "POST":
# 将 FastAPI 接收到的 FormData 转换为 WTForms 需要的格式
form_data = await request.form()
form = DemoForm(form_data)
if form.validate():
print("city:", form.city.data)
print("gender:", form.gender.data)
print("bio:", form.bio.data)
# 返回成功
return JSONResponse({"status_code": 200, "detail": "提交成功", "data": {}})
else:
print(form.errors)
error_msg = "; ".join([f"{field}: {', '.join(errors)}" for field, errors in form.errors.items()])
# 返回异常
return JSONResponse({"status_code": 400, "detail": error_msg, "data": {}})
html:
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>FastAPI + WTForms 动态表单</title>
<!-- 引入简易 CSS 框架让页面好看一点 -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@example/water.css@2/out/water.css">
<style>
.error-msg { color: #ff4d4f; font-size: 0.9em; margin-top: 5px; }
.radio-group { display: flex; gap: 15px; align-items: center; margin: 10px 0; }
.radio-item { display: inline-flex; align-items: center; gap: 5px; }
.success-box { background-color: #e6f7ff; border: 1px solid #91d5ff; padding: 15px; border-radius: 4px; margin-bottom: 20px; }
.form-radio {
list-style-type: none;
padding-inline-start: 0px;
padding-top: 6px;
display: flex;
gap: 20px;
}
</style>
</head>
<body>
<h2>FastAPI + WTForms 动态表单示例</h2>
<!-- 显示提交成功后的结果 -->
{% if result %}
<div class="success-box">
<strong>{{ result }}</strong>
</div>
{% endif %}
<form method="POST" action="">
<!-- 1. 动态生成 Select 下拉框 -->
<div style="margin-bottom: 20px;">
<label>{{ form.city.label }}</label>
{{ form.city(class="form-select") }}
{% if form.city.errors %}
{% for error in form.city.errors %}
<div class="error-msg">{{ error }}</div>
{% endfor %}
{% endif %}
</div>
<!-- 2. 动态生成 Radio 单选框 Radio 需要循环遍历里面的选项单独渲染
<div style="margin-bottom: 20px;">
<label>{{ form.gender.label }}</label>
<div class="radio-group">
{% for subfield in form.gender %}
<span class="radio-item">
{{ subfield }}
{{ subfield.label }}
</span>
{% endfor %}
</div>
{% if form.gender.errors %}
{% for error in form.gender.errors %}
<div class="error-msg">{{ error }}</div>
{% endfor %}
{% endif %}
</div>
-->
<!-- 2. 动态生成 Radio 单选框 -->
<div style="margin-bottom: 20px;">
<label>{{ form.gender.label }}</label>
{{ form.gender(class="form-radio") }}
{% if form.gender.errors %}
{% for error in form.gender.errors %}
<div class="error-msg">{{ error }}</div>
{% endfor %}
{% endif %}
</div>
<!-- 3. 动态生成 Textarea 多行文本 -->
<div style="margin-bottom: 20px;">
<label>{{ form.bio.label }}</label>
<!-- 可以在括号里直接控制 rows 和 cols 等 HTML 属性 -->
{{ form.bio(rows="5", style="width: 100%;") }}
{% if form.bio.errors %}
{% for error in form.bio.errors %}
<div class="error-msg">{{ error }}</div>
{% endfor %}
{% endif %}
</div>
<button type="submit">提交表单</button>
</form>
</body>
</html>
三,测试效果:
页面:

接收到的数据:
city: 1
gender: 0
bio: 上海,女
浙公网安备 33010602011771号