"Si un trabajador quiere hacer bien su trabajo, primero debe afilar sus herramientas." - Confucio, "Las Analectas de Confucio. Lu Linggong"
Página delantera > Programación > FastAPI: Cómo utilizar Pydantic para declarar parámetros de consulta

FastAPI: Cómo utilizar Pydantic para declarar parámetros de consulta

Publicado el 2024-11-19
Navegar:971

Hace unas tres semanas salió a la luz una de las características más esperadas de FastAPI. Al menos cuando hablamos de Pydantic Models FastAPI.

Sí, me refiero a la capacidad de utilizar modelos Pydantic para asignar sus parámetros de consulta.

Entonces, en esta publicación, intentaré mostrártelos todos. puede y ? ¿Qué no puedo hacer con este tema?:

? Parámetros de consulta de asignación

Lo primero que debe hacer para comenzar a mapear sus parámetros de consulta con Pydantic es asegurarse de que está utilizando FastAPI versión 0.115.0.

Después de esto, siempre puedes ir a los documentos de FastAPI para verificar lo que ya está disponible. Sebastián y los miembros del equipo hacen un muy, muy buen trabajo manteniendo los documentos actualizados e informativos ✨.

? Un poco de Historia

Comencemos con algunos ejemplos sobre cómo solíamos asignar parámetros de consulta en FastAPI. ?

La forma más sencilla de hacerlo sería:

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
    }

Y ahora puedes simplemente llamar:

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

Pero si identificamos que estos parámetros de consulta se usarían en otras rutas, lo aislaríamos con algo como:

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

O como estamos usando Pydantic para mapear nuestros modelos, con solo una pequeña refactorización obtendríamos:

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

⌨️ Usando Pydantic para mapear las cadenas de consulta

FastAPI: How to use Pydantic to declare Query Parameters

Ahora, si queremos obtener nuestra cadena de consulta, no necesitamos crear una función y luego agregarla como una dependencia. Simplemente podemos decirle a FastAPI que queremos un objeto de tipo PaginationQueryString y que es una cadena de consulta:

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

Fácil, ¿verdad? ?

⚠️ ¿Cuáles son las limitaciones?

Al menos en la versión 0.115.0, no funciona muy bien con modelos anidados.

Probemos algo como:

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 lo llamamos como antes:

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

Recibiremos un error que nos indica que el filtro es un objeto:

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

¡Al menos ahora mismo, es absolutamente correcto! Cambiamos nuestro filtro para que sea un modelo Pydantic, no una cadena. Pero si intentamos convertirlo a un diccionario:

http://localhost:8000/?limit=42&skip=12&filter={"name": "Rafael", "age": 38, "nickname": "ceb10n"}

FastAPI nos dirá que el filtro debe ser un diccionario válido:

{
    "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\"}"
        }
    ]
}

Esto sucede porque FastAPI dependerá de QueryParams de Starlette, que le dará una cadena a FastAPI, no un dict. Y al menos en la versión 0.115.0, esto te dará un error.

⁉️ Entonces, ¿cuándo debo utilizar modelos de Pydantic con mis parámetros de consulta?

Es bastante simple:

✅ ¿Tiene cadenas de consulta simples que no necesitan ningún objeto anidado sofisticado y elaborado? ¡Úselo! ?

❌ ¿Creaste una cadena de consulta anidada compleja? ¿Aún no lo usas?. (Y tal vez debería intentar reconsiderar sus cadenas de consulta. ¿Cuanto más simples, mejor?)

Declaración de liberación Este artículo se reproduce en: https://dev.to/ceb10n/fastapi-how-to-use-pydantic-to-declare-query-parameters-25bd?1 Si hay alguna infracción, comuníquese con [email protected] para borrarlo
Último tutorial Más>

Descargo de responsabilidad: Todos los recursos proporcionados provienen en parte de Internet. Si existe alguna infracción de sus derechos de autor u otros derechos e intereses, explique los motivos detallados y proporcione pruebas de los derechos de autor o derechos e intereses y luego envíelos al correo electrónico: [email protected]. Lo manejaremos por usted lo antes posible.

Copyright© 2022 湘ICP备2022001581号-3