Maison  >  Article  >  développement back-end  >  FastAPI : Comment utiliser Pydantic pour déclarer les paramètres de requête

FastAPI : Comment utiliser Pydantic pour déclarer les paramètres de requête

Linda Hamilton
Linda Hamiltonoriginal
2024-10-10 06:11:30759parcourir

Il y a environ trois semaines, l'une des fonctionnalités les plus attendues de FastAPI est sortie. Au moins quand nous parlons de Pydantic Models FastAPI.

Oui, je parle de la possibilité d'utiliser des modèles Pydantic pour mapper vos paramètres de requête.

Alors dans ce post, je vais essayer de tout vous montrer ? peut et ? je n'y peux rien sur ce sujet ?:

? Paramètres de requête de mappage

La première chose que vous devez faire pour commencer à mapper vos paramètres de requête avec Pydantic est de vous assurer que vous utilisez FastAPI version 0.115.0.

Après cela, vous pouvez toujours accéder à la documentation FastAPI pour vérifier ce qui est déjà disponible. Sebastián et les membres de l'équipe font un très, très bon travail pour maintenir les documents à jour et informatifs ✨.

? Un peu d'Histoire

Commençons par quelques exemples de la façon dont nous mappons les paramètres de requête dans FastAPI. ?

La façon la plus simple de le faire serait :

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def search(
    limit: int | None = 10,
    skip: int | None = 1,
    filter: str | None = None
):
    return {
        "limit": limit,
        "skip": skip,
        "filter": filter
    }

Et maintenant, vous pouvez simplement appeler :

GET http://localhost:8000/?limit=42&skip=12&filter=banana

Mais si nous identifiions que ces paramètres de requête seraient utilisés dans d'autres routes, nous les isolerions avec quelque chose comme :

from typing import Any
from fastapi import Depends, FastAPI, Query

app = FastAPI()

async def pagination_query_string(
    limit: int | None = Query(10, ge=5, le=100),
    skip: int | None = Query(1, ge=1),
    filter: str | None = Query(None)
) -> dict[str, Any]:
    return {
        "limit": limit,
        "skip": skip,
        "filter": filter
    }

@app.get("/")
async def search(q: dict[str, Any] = Depends(pagination_query_string)):
    return q

Ou puisque nous utilisons Pydantic pour cartographier nos modèles, avec juste un peu de refactorisation, nous obtiendrions :

from fastapi import Depends, FastAPI, Query
from pydantic import BaseModel

app = FastAPI()

class PaginationQueryString(BaseModel):
    limit: int | None = 10
    skip: int | None = 1
    filter: str | None = None

async def pagination_query_string(
    limit: int | None = Query(10, ge=5, le=100),
    skip: int | None = Query(1, ge=1),
    filter: str | None = Query(None)
) -> PaginationQueryString:
    return PaginationQueryString(
        limit=limit,
        skip=skip,
        filter=filter
    )

@app.get("/")
async def search(q: PaginationQueryString = Depends(pagination_query_string)):
    return q

⌨️ Utiliser Pydantic pour mapper les chaînes de requête

FastAPI: How to use Pydantic to declare Query Parameters

Maintenant, si nous voulons obtenir notre chaîne de requête, nous n'avons pas besoin de créer une fonction puis de l'ajouter en tant que dépendance. On peut simplement dire à FastAPI que l'on veut un objet de type PaginationQueryString et que c'est une chaîne de requête :

from typing import Annotated
from fastapi import FastAPI, Query
from pydantic import BaseModel

app = FastAPI()

class PaginationQueryString(BaseModel):
    limit: int | None = 10
    skip: int | None = 1
    filter: str | None = None

@app.get("/")
async def search(q: Annotated[PaginationQueryString, Query()]):
    return q

Facile, non ? ?

⚠️ Quelles sont les limites ?

Au moins dans la version 0.115.0, cela ne fonctionne pas très bien avec les modèles imbriqués.

Essayons quelque chose comme :

from typing import Annotated
from fastapi import FastAPI, Query
from pydantic import BaseModel

app = FastAPI()

class Filter(BaseModel):
    name: str | None = None
    age: int | None = None
    nickname: str | None = None

class PaginationQueryString(BaseModel):
    limit: int | None = 10
    skip: int | None = 1
    filter: Filter | None = None

@app.get("/")
async def search(q: Annotated[PaginationQueryString, Query()]):
    return q

Si on l'appelle comme avant :

GET http://localhost:8000/?limit=42&skip=12&filter=chocolate

Nous aurons une erreur nous indiquant que le filtre est un objet :

{
    "detail": [
        {
            "type": "model_attributes_type",
            "loc": [
                "query",
                "filter"
            ],
            "msg": "Input should be a valid dictionary or object to extract fields from",
            "input": "chocolate"
        }
    ]
}

Au moins pour le moment, c'est tout à fait vrai ! Nous avons changé notre filtre pour qu'il soit un modèle Pydantic, pas une chaîne. Mais si on essaie de le convertir en dictionnaire :

http://localhost:8000/?limit=42&skip=12&filter={%22name%22:%20%22Rafael%22,%20%22age%22:%2038,%20%22nickname%22:%20%22ceb10n%22}

FastAPI nous dira que le filtre doit être un dictionnaire valide ?:

{
    "detail": [
        {
            "type": "model_attributes_type",
            "loc": [
                "query",
                "filter"
            ],
            "msg": "Input should be a valid dictionary or object to extract fields from",
            "input": "{\"name\": \"Rafael\", \"age\": 38, \"nickname\": \"ceb10n\"}"
        }
    ]
}

Cela se produit parce que FastAPI s'appuiera sur QueryParams de Starlette, qui donnera une chaîne à FastAPI, pas un dict. Et au moins dans la version 0.115.0, cela vous donnera une erreur.

⁉️ Alors, quand dois-je utiliser les modèles Pydantic avec mes paramètres de requête ?

C'est assez simple :

✅ Vous disposez de chaînes de requête simples qui ne nécessitent pas d'objets imbriqués sophistiqués et sophistiqués ? Utilisez-le ! ?

❌ Vous avez créé une chaîne de requête imbriquée complexe ? Vous ne l'utilisez pas encore ?. (Et peut-être devriez-vous essayer de repenser vos chaînes de requête. ? Le plus simple, le mieux ?)

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn