Aller au contenu

Modèles de formulaire

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.

🌐 Traduction par IA et humains

Cette traduction a été réalisée par une IA guidée par des humains. 🤝

Elle peut contenir des erreurs d'interprétation du sens original, ou paraître peu naturelle, etc. 🤖

Vous pouvez améliorer cette traduction en nous aidant à mieux guider le LLM d'IA.

Version anglaise

Vous pouvez utiliser des modèles Pydantic pour déclarer des champs de formulaire dans FastAPI.

Remarque

Pour utiliser les formulaires, installez d'abord python-multipart.

Ajoutez-le à votre projet :

$ uv add python-multipart

Remarque

Ceci est pris en charge depuis la version 0.113.0 de FastAPI. 🤓

Modèles Pydantic pour les formulaires

Vous avez simplement besoin de déclarer un modèle Pydantic avec les champs que vous souhaitez recevoir comme champs de formulaire, puis de déclarer le paramètre comme 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 va extraire les données pour chaque champ à partir des données de formulaire de la requête et vous fournir le modèle Pydantic que vous avez défini.

Pour les cases à cocher HTML, déclarez des champs booléens avec une valeur par défaut de False.

Consultez les documents

Vous pouvez le vérifier dans l'interface des documents à /docs :

Interdire les champs de formulaire supplémentaires

Dans certains cas d'utilisation particuliers (probablement peu courants), vous pourriez vouloir restreindre les champs de formulaire à ceux déclarés dans le modèle Pydantic. Et interdire tout champ supplémentaire.

Remarque

Ceci est pris en charge depuis la version 0.114.0 de FastAPI. 🤓

Vous pouvez utiliser la configuration du modèle Pydantic pour forbid tout champ 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 client tente d'envoyer des données supplémentaires, il recevra une réponse d'erreur.

Par exemple, si le client essaie d'envoyer les champs de formulaire :

  • username: Rick
  • password: Portal Gun
  • extra: Mr. Poopybutthole

Il recevra une réponse d'erreur lui indiquant que le champ extra n'est pas autorisé :

{
    "detail": [
        {
            "type": "extra_forbidden",
            "loc": ["body", "extra"],
            "msg": "Extra inputs are not permitted",
            "input": "Mr. Poopybutthole"
        }
    ]
}

Combiner des modèles de formulaire

Vous pouvez combiner plusieurs modèles de formulaire avec des paramètres Form individuels.

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}

Le client envoie name, tags et token comme champs de formulaire. Chaque modèle valide les champs de formulaire indépendamment.

La configuration extra de chaque modèle s'applique à tous les champs de formulaire, y compris les champs et les fichiers déclarés dans d'autres paramètres ou dépendances. Avec extra="forbid", tout champ extérieur à ce modèle est rejeté. Avec extra="allow", ces champs sont inclus comme données supplémentaires du modèle.

Si plusieurs déclarations utilisent le même nom de champ de formulaire, chacune valide la valeur de ce champ. Utilisez des types et des contraintes compatibles pour les champs partagés afin que le schéma OpenAPI puisse les décrire de manière cohérente.

Modèles de formulaire optionnels

Déclarez un modèle de formulaire avec | None et une valeur par défaut de None pour rendre le groupe optionnel.

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 ni name ni age ne sont envoyés, profile vaut None. Si l'un des deux est envoyé, FastAPI valide le modèle et exige les deux champs. Une valeur vide soumise compte également comme un champ fourni.

Utiliser | None sans valeur par défaut laisse le paramètre obligatoire.

Les champs supplémentaires suivent la configuration extra du modèle. Les champs supplémentaires ignorés ne rendent pas le modèle présent.

Un modèle optionnel ne contenant que des cases à cocher non cochées est omis. Envoyez une valeur telle que enabled=false pour le fournir explicitement.

Unions optionnelles de modèles de formulaire

Vous pouvez également utiliser une union optionnelle de modèles.

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 aucun champ de formulaire n'est envoyé, contact vaut None. Envoyez kind=person avec name, ou kind=company avec company_name. Le discriminateur sélectionne le modèle à valider.

Combiner des unions de modèles de formulaire

Vous pouvez combiner des unions avec d'autres modèles de formulaire, des paramètres Form individuels et des paramètres File. Chaque union est validée indépendamment.

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}

Envoyez tous les champs dans le même formulaire. Par exemple, envoyez contact_type=person, name=Rick, notification_type=email, email=rick@example.com et token=secret.

Omettez les champs de notification pour laisser notification à None.

Modèles de formulaire et fichiers

Vous pouvez également combiner un modèle de formulaire avec des paramètres de fichier.

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}

Ici, le client envoie le champ name et le fichier avatar en utilisant multipart/form-data.

Résumer

Vous pouvez utiliser des modèles Pydantic pour déclarer des champs de formulaire dans FastAPI. 😎