First Form¶
A form is a Pydantic model. Subclass FormModel, declare the fields, and
render it.
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
from pydantic_schemaforms import Field, FormModel, render_form_html_async
class SignupForm(FormModel):
name: str = Field(title='Full name')
email: str = Field(title='Email', ui_element='email')
app = FastAPI()
@app.get('/signup', response_class=HTMLResponse)
async def show_signup():
return await render_form_html_async(
SignupForm,
submit_url='/signup',
include_framework_assets=True,
asset_mode='cdn',
)
from flask import Flask
from pydantic_schemaforms import Field, FormModel, render_form_html
class SignupForm(FormModel):
name: str = Field(title='Full name')
email: str = Field(title='Email', ui_element='email')
app = Flask(__name__)
@app.get('/signup')
def show_signup():
return render_form_html(
SignupForm,
submit_url='/signup',
include_framework_assets=True,
asset_mode='cdn',
)
Run it and open /signup: you get a styled form with a "Full name" text box,
an "Email" box and a submit button.
What's going on¶
SignupForm(FormModel) is an ordinary Pydantic model. FormModel adds
the form rendering and validation on top, so the same class can still be
used anywhere a Pydantic model can.
Field(title=...) works like Pydantic's Field and adds the form
settings. title becomes the field's label; without it the label comes from
the field name (email becomes "Email").
ui_element="email" picks the input type. Without it, the library picks
one from the field's type: str gets a text box, bool a checkbox, date a
date picker. Fields and Inputs covers this in detail.
render_form_html_async() returns the form as an HTML string, including
its labels, inline validation script and the submit button. The FastAPI
example uses the async version so rendering doesn't block the event loop;
Flask uses the plain render_form_html().
submit_url is required: it's where the form posts to. The library never
guesses a default.
include_framework_assets=True, asset_mode="cdn" adds the <link> and
<script> tags that load Bootstrap from a CDN, so this one string is a
working page. In a real app your page template already loads Bootstrap: drop
these two options and put the form into your template.
Putting the form in your own page template
render_form_html() returns a plain string of trusted HTML. In a Jinja
template, mark it safe so Jinja doesn't escape it:
<main class="container">
<h1>Sign up</h1>
{{ form_html | safe }}
</main>
Never build the page around it with an f-string if the page also shows anything the user typed; see Handling Submissions. The Jinja template recipe has a complete example.
Rendering from the model class
SignupForm.render_form(submit_url="/signup") does the same as
render_form_html(SignupForm, submit_url="/signup"). The docs use
render_form_html() throughout because it has an async version.
Next: Handling Submissions.