pythonasyncioapiasyncfastapiframeworkjsonjson-schemaopenapiopenapi3pydanticpython-typespython3redocreststarletteswaggerswagger-uiuvicornweb
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
60 lines
1.8 KiB
60 lines
1.8 KiB
from fastapi import FastAPI, Form, Request
|
|
from fastapi.responses import HTMLResponse
|
|
from fastapi.templating import Jinja2Templates
|
|
from jinja2 import DictLoader, Environment
|
|
from pydantic import BaseModel, ValidationInfo, model_validator
|
|
|
|
|
|
class MyModel(BaseModel):
|
|
checkbox: bool = True
|
|
|
|
@model_validator(mode="before")
|
|
def handle_defaults(cls, value: dict, info: ValidationInfo) -> dict:
|
|
# if this model is being used outside of fastapi, return normally
|
|
if info.context is None or "fastapi_field" not in info.context:
|
|
return value
|
|
|
|
# check if we are being validated from form input,
|
|
# and if so, treat the unset checkbox as False
|
|
field_info = info.context["fastapi_field"].field_info
|
|
is_form = type(field_info).__name__ == "Form"
|
|
if is_form and "checkbox" not in value:
|
|
value["checkbox"] = False
|
|
return value
|
|
|
|
|
|
form_template = """
|
|
<form action="/form" method="POST">
|
|
{% for field_name, field in model.model_fields.items() %}
|
|
<p>
|
|
<label for="{{ field_name }}">{{ field_name }}</label>
|
|
{% if field.annotation.__name__ == "bool" %}
|
|
<input type="checkbox" name="{{field_name}}"
|
|
{% if field.default %}
|
|
checked="checked"
|
|
{% endif %}
|
|
>
|
|
{% else %}
|
|
<input name="{{ field_name }}">
|
|
{% endif %}
|
|
</p>
|
|
{% endfor %}
|
|
<button type="submit">Submit</button>
|
|
</form>
|
|
"""
|
|
loader = DictLoader({"form.html": form_template})
|
|
templates = Jinja2Templates(env=Environment(loader=loader))
|
|
|
|
app = FastAPI()
|
|
|
|
|
|
@app.get("/form", response_class=HTMLResponse)
|
|
async def show_form(request: Request):
|
|
return templates.TemplateResponse(
|
|
request=request, name="form.html", context={"model": MyModel}
|
|
)
|
|
|
|
|
|
@app.post("/form")
|
|
async def submit_form(data: MyModel = Form()) -> MyModel:
|
|
return data
|
|
|