Modelos de Formulario¶
AI coding agents
Use the official FastAPI skill for your installed version. Install it from your project directory:
uvx library-skills
See Develop with AI.
🌐 Traducción por IA y humanos
Esta traducción fue hecha por IA guiada por humanos. 🤝
Podría tener errores al interpretar el significado original, o sonar poco natural, etc. 🤖
Puedes mejorar esta traducción ayudándonos a guiar mejor al LLM de IA.
Puedes usar modelos de Pydantic para declarar campos de formulario en FastAPI.
Nota
Para usar formularios, primero instala python-multipart.
Agrégalo a tu proyecto:
$ uv add python-multipart
Nota
Esto es compatible desde la versión 0.113.0 de FastAPI. 🤓
Modelos de Pydantic para Formularios¶
Solo necesitas declarar un modelo de Pydantic con los campos que quieres recibir como campos de formulario, y luego declarar el parámetro como Form:
from typing import Annotated
from fastapi import FastAPI, Form
from pydantic import BaseModel
app = FastAPI()
class FormData(BaseModel):
username: str
password: str
@app.post("/login/")
async def login(data: Annotated[FormData, Form()]):
return data
🤓 Other versions and variants
Tip
Prefer to use the Annotated version if possible.
from fastapi import FastAPI, Form
from pydantic import BaseModel
app = FastAPI()
class FormData(BaseModel):
username: str
password: str
@app.post("/login/")
async def login(data: FormData = Form()):
return data
FastAPI extraerá los datos de cada campo de los form data en el request y te dará el modelo de Pydantic que definiste.
Para las casillas de verificación HTML, declara campos booleanos con un valor por defecto de False.
Revisa la Documentación¶
Puedes verificarlo en la interfaz de documentación en /docs:
Prohíbe Campos de Formulario Extra¶
En algunos casos de uso especiales (probablemente no muy comunes), podrías querer restringir los campos de formulario a solo aquellos declarados en el modelo de Pydantic. Y prohibir cualquier campo extra.
Nota
Esto es compatible desde la versión 0.114.0 de FastAPI. 🤓
Puedes usar la configuración del modelo de Pydantic para forbid cualquier campo extra:
from typing import Annotated
from fastapi import FastAPI, Form
from pydantic import BaseModel
app = FastAPI()
class FormData(BaseModel):
username: str
password: str
model_config = {"extra": "forbid"}
@app.post("/login/")
async def login(data: Annotated[FormData, Form()]):
return data
🤓 Other versions and variants
Tip
Prefer to use the Annotated version if possible.
from fastapi import FastAPI, Form
from pydantic import BaseModel
app = FastAPI()
class FormData(BaseModel):
username: str
password: str
model_config = {"extra": "forbid"}
@app.post("/login/")
async def login(data: FormData = Form()):
return data
Si un cliente intenta enviar datos extra, recibirá un response de error.
Por ejemplo, si el cliente intenta enviar los campos de formulario:
username:Rickpassword:Portal Gunextra:Mr. Poopybutthole
Recibirá un response de error indicando que el campo extra no está permitido:
{
"detail": [
{
"type": "extra_forbidden",
"loc": ["body", "extra"],
"msg": "Extra inputs are not permitted",
"input": "Mr. Poopybutthole"
}
]
}
Combina Modelos de Formulario¶
Puedes combinar varios modelos de formulario con parámetros Form individuales.
from typing import Annotated
from fastapi import FastAPI, Form
from pydantic import BaseModel
app = FastAPI()
class Profile(BaseModel):
name: str
class Preferences(BaseModel):
tags: list[str] = []
@app.post("/profiles/")
async def create_profile(
profile: Annotated[Profile, Form()],
preferences: Annotated[Preferences, Form()],
token: Annotated[str, Form()],
):
return {"profile": profile, "preferences": preferences, "token": token}
🤓 Other versions and variants
Tip
Prefer to use the Annotated version if possible.
from fastapi import FastAPI, Form
from pydantic import BaseModel
app = FastAPI()
class Profile(BaseModel):
name: str
class Preferences(BaseModel):
tags: list[str] = []
@app.post("/profiles/")
async def create_profile(
profile: Profile = Form(),
preferences: Preferences = Form(),
token: str = Form(),
):
return {"profile": profile, "preferences": preferences, "token": token}
El cliente envía name, tags y token como campos de formulario. Cada modelo valida los campos de formulario de forma independiente.
La configuración extra de cada modelo se aplica a todos los campos de formulario, incluidos los campos y archivos declarados en otros parámetros o dependencias. Con extra="forbid", se rechaza cualquier campo que no forme parte de ese modelo. Con extra="allow", esos campos se incluyen como campos extra del modelo.
Si varias declaraciones usan el mismo nombre de campo de formulario, cada una valida el valor de ese campo. Usa tipos y restricciones compatibles para los campos compartidos, de modo que el esquema OpenAPI pueda describirlos de forma coherente.
Modelos de Formulario Opcionales¶
Declara un modelo de formulario con | None y un valor por defecto de None para hacer que el grupo sea opcional.
from typing import Annotated
from fastapi import FastAPI, Form
from pydantic import BaseModel
app = FastAPI()
class Profile(BaseModel):
name: str
age: int
@app.post("/profiles/")
async def create_profile(
token: Annotated[str, Form()],
profile: Annotated[Profile | None, Form()] = None,
):
return {"token": token, "profile": profile}
🤓 Other versions and variants
Tip
Prefer to use the Annotated version if possible.
from fastapi import FastAPI, Form
from pydantic import BaseModel
app = FastAPI()
class Profile(BaseModel):
name: str
age: int
@app.post("/profiles/")
async def create_profile(
token: str = Form(),
profile: Profile | None = Form(default=None),
):
return {"token": token, "profile": profile}
Si no se envía ni name ni age, profile es None. Si se envía cualquiera de los dos, FastAPI valida el modelo y requiere ambos campos. Enviar un valor vacío también cuenta como proporcionar un campo.
Usar | None sin un valor por defecto sigue haciendo que el parámetro sea obligatorio.
Los campos extra siguen la configuración extra del modelo. Los campos extra ignorados no hacen que el modelo se considere presente.
Un modelo opcional que solo contiene casillas de verificación sin marcar se omite. Envía un valor como enabled=false para proporcionarlo explícitamente.
Uniones Opcionales de Modelos de Formulario¶
También puedes usar una unión opcional de modelos.
from typing import Annotated, Literal
from fastapi import FastAPI, Form
from pydantic import BaseModel
app = FastAPI()
class Person(BaseModel):
kind: Literal["person"]
name: str
class Company(BaseModel):
kind: Literal["company"]
company_name: str
@app.post("/contacts/")
async def create_contact(
contact: Annotated[Person | Company | None, Form(discriminator="kind")] = None,
):
return contact
🤓 Other versions and variants
Tip
Prefer to use the Annotated version if possible.
from typing import Literal
from fastapi import FastAPI, Form
from pydantic import BaseModel
app = FastAPI()
class Person(BaseModel):
kind: Literal["person"]
name: str
class Company(BaseModel):
kind: Literal["company"]
company_name: str
@app.post("/contacts/")
async def create_contact(
contact: Person | Company | None = Form(default=None, discriminator="kind"),
):
return contact
Si no se envían campos de formulario, contact es None. Envía kind=person con name, o kind=company con company_name. El discriminador selecciona qué modelo validar.
Combina Uniones de Modelos de Formulario¶
Puedes combinar uniones con otros modelos de formulario, parámetros Form individuales y parámetros File. Cada unión se valida de forma independiente.
from typing import Annotated, Literal
from fastapi import FastAPI, Form
from pydantic import BaseModel
app = FastAPI()
class Person(BaseModel):
contact_type: Literal["person"]
name: str
class Company(BaseModel):
contact_type: Literal["company"]
company_name: str
class Email(BaseModel):
notification_type: Literal["email"]
email: str
class SMS(BaseModel):
notification_type: Literal["sms"]
phone: str
@app.post("/contacts/")
async def create_contact(
contact: Annotated[Person | Company, Form(discriminator="contact_type")],
token: Annotated[str, Form()],
notification: Annotated[
Email | SMS | None, Form(discriminator="notification_type")
] = None,
):
return {"contact": contact, "notification": notification, "token": token}
🤓 Other versions and variants
Tip
Prefer to use the Annotated version if possible.
from typing import Literal
from fastapi import FastAPI, Form
from pydantic import BaseModel
app = FastAPI()
class Person(BaseModel):
contact_type: Literal["person"]
name: str
class Company(BaseModel):
contact_type: Literal["company"]
company_name: str
class Email(BaseModel):
notification_type: Literal["email"]
email: str
class SMS(BaseModel):
notification_type: Literal["sms"]
phone: str
@app.post("/contacts/")
async def create_contact(
contact: Person | Company = Form(discriminator="contact_type"),
token: str = Form(),
notification: Email | SMS | None = Form(
default=None, discriminator="notification_type"
),
):
return {"contact": contact, "notification": notification, "token": token}
Envía todos los campos en el mismo formulario. Por ejemplo, envía contact_type=person, name=Rick, notification_type=email, email=rick@example.com y token=secret.
Omite los campos de notificación para dejar notification como None.
Modelos de Formulario y Archivos¶
También puedes combinar un modelo de formulario con parámetros de archivo.
from typing import Annotated
from fastapi import FastAPI, Form, UploadFile
from pydantic import BaseModel
app = FastAPI()
class Profile(BaseModel):
name: str
@app.post("/profiles/")
async def create_profile(profile: Annotated[Profile, Form()], avatar: UploadFile):
return {"profile": profile, "filename": avatar.filename}
🤓 Other versions and variants
Tip
Prefer to use the Annotated version if possible.
from fastapi import FastAPI, File, Form, UploadFile
from pydantic import BaseModel
app = FastAPI()
class Profile(BaseModel):
name: str
@app.post("/profiles/")
async def create_profile(profile: Profile = Form(), avatar: UploadFile = File()):
return {"profile": profile, "filename": avatar.filename}
Aquí el cliente envía el campo name y el archivo avatar usando multipart/form-data.
Resumen¶
Puedes usar modelos de Pydantic para declarar campos de formulario en FastAPI. 😎