Saltar a contenido

Modelos de Parámetros Query

🌐 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.

Versión en inglés

Si tienes un grupo de parámetros query que están relacionados, puedes crear un modelo de Pydantic para declararlos.

Esto te permitiría reutilizar el modelo en múltiples lugares y también declarar validaciones y metadatos para todos los parámetros de una vez. 😎

Nota

Esto es compatible desde la versión 0.115.0 de FastAPI. 🤓

Parámetros Query con un Modelo Pydantic

Declara los parámetros query que necesitas en un modelo de Pydantic, y luego declara el parámetro como Query:

from typing import Annotated, Literal

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

app = FastAPI()


class FilterParams(BaseModel):
    limit: int = Field(100, gt=0, le=100)
    offset: int = Field(0, ge=0)
    order_by: Literal["created_at", "updated_at"] = "created_at"
    tags: list[str] = []


@app.get("/items/")
async def read_items(filter_query: Annotated[FilterParams, Query()]):
    return filter_query
🤓 Other versions and variants

Tip

Prefer to use the Annotated version if possible.

from typing import Literal

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

app = FastAPI()


class FilterParams(BaseModel):
    limit: int = Field(100, gt=0, le=100)
    offset: int = Field(0, ge=0)
    order_by: Literal["created_at", "updated_at"] = "created_at"
    tags: list[str] = []


@app.get("/items/")
async def read_items(filter_query: FilterParams = Query()):
    return filter_query

FastAPI extraerá los datos para cada campo de los parámetros query en el request y te proporcionará el modelo de Pydantic que definiste.

Revisa la Documentación

Puedes ver los parámetros query en la UI de documentación en /docs:

Prohíbe Parámetros Query Extras

En algunos casos de uso especiales (probablemente no muy comunes), podrías querer restringir los parámetros query que deseas recibir.

Puedes usar la configuración del modelo de Pydantic para forbid cualquier campo extra:

from typing import Annotated, Literal

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

app = FastAPI()


class FilterParams(BaseModel):
    model_config = {"extra": "forbid"}

    limit: int = Field(100, gt=0, le=100)
    offset: int = Field(0, ge=0)
    order_by: Literal["created_at", "updated_at"] = "created_at"
    tags: list[str] = []


@app.get("/items/")
async def read_items(filter_query: Annotated[FilterParams, Query()]):
    return filter_query
🤓 Other versions and variants

Tip

Prefer to use the Annotated version if possible.

from typing import Literal

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

app = FastAPI()


class FilterParams(BaseModel):
    model_config = {"extra": "forbid"}

    limit: int = Field(100, gt=0, le=100)
    offset: int = Field(0, ge=0)
    order_by: Literal["created_at", "updated_at"] = "created_at"
    tags: list[str] = []


@app.get("/items/")
async def read_items(filter_query: FilterParams = Query()):
    return filter_query

Si un cliente intenta enviar algunos datos extra en los parámetros query, recibirá un response de error.

Por ejemplo, si el cliente intenta enviar un parámetro query tool con un valor de plumbus, como:

https://example.com/items/?limit=10&tool=plumbus

Recibirá un response de error que le indica que el parámetro query tool no está permitido:

{
    "detail": [
        {
            "type": "extra_forbidden",
            "loc": ["query", "tool"],
            "msg": "Extra inputs are not permitted",
            "input": "plumbus"
        }
    ]
}

Combina Modelos de Parámetros

Puedes declarar múltiples modelos de parámetros query y combinarlos con parámetros query individuales o dependencias.

from typing import Annotated

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

app = FastAPI()


class Pagination(BaseModel):
    limit: int = Field(10, ge=1)
    offset: int = Field(0, ge=0)


class Filters(BaseModel):
    tags: list[str] = []


@app.get("/items/")
def read_items(
    pagination: Annotated[Pagination, Query()],
    filters: Annotated[Filters, Query()],
    search: str | None = None,
):
    return {"pagination": pagination, "filters": filters, "search": search}
🤓 Other versions and variants

Tip

Prefer to use the Annotated version if possible.

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

app = FastAPI()


class Pagination(BaseModel):
    limit: int = Field(10, ge=1)
    offset: int = Field(0, ge=0)


class Filters(BaseModel):
    tags: list[str] = []


@app.get("/items/")
def read_items(
    pagination: Pagination = Query(),
    filters: Filters = Query(),
    search: str | None = None,
):
    return {"pagination": pagination, "filters": filters, "search": search}

Los parámetros del request permanecen en el mismo nivel.

https://example.com/items/?limit=5&offset=10&tags=red&tags=blue&search=shirt

No hay claves pagination ni filters en el query string. Cada modelo valida los parámetros query de forma independiente, con sus propios valores por defecto, validadores de campos y validadores de modelo. Lo mismo se aplica cuando los modelos o los parámetros individuales se declaran en dependencias.

Si los modelos comparten un nombre de parámetro o un alias, cada modelo valida ese parámetro del request de forma independiente. Usa nombres o alias distintos para valores independientes. OpenAPI muestra un parámetro compartido una sola vez, como hace con los parámetros compartidos con dependencias, por lo que las declaraciones compartidas deben describir el mismo tipo y las mismas restricciones.

La configuración extra de cada modelo se aplica a todos los parámetros query, incluidos los declarados en otros modelos o dependencias. Con extra="forbid", se rechaza cualquier parámetro ajeno a ese modelo. Con extra="allow", esos parámetros se incluyen como extras del modelo.

Esto también funciona para los modelos de Header y Cookie.

Modelos Opcionales de Parámetros Query

Declara un modelo de parámetros query con | None y un valor por defecto de None para hacer que el grupo sea opcional.

from datetime import date
from typing import Annotated

from fastapi import FastAPI, Query
from pydantic import BaseModel

app = FastAPI()


class DateRange(BaseModel):
    start: date
    end: date


@app.get("/items/")
async def read_items(
    limit: int = 10,
    date_range: Annotated[DateRange | None, Query()] = None,
):
    return {"limit": limit, "date_range": date_range}
🤓 Other versions and variants

Tip

Prefer to use the Annotated version if possible.

from datetime import date

from fastapi import FastAPI, Query
from pydantic import BaseModel

app = FastAPI()


class DateRange(BaseModel):
    start: date
    end: date


@app.get("/items/")
async def read_items(
    limit: int = 10,
    date_range: DateRange | None = Query(default=None),
):
    return {"limit": limit, "date_range": date_range}

Si no se envía ni start ni end, date_range es None. Si se envía cualquiera de los dos, FastAPI valida el modelo y requiere ambos campos.

Usar | None sin un valor por defecto sigue haciendo que el parámetro sea obligatorio.

Los parámetros extra siguen la configuración extra del modelo. Los extras ignorados no hacen que el modelo se considere presente.

OpenAPI muestra los campos del grupo individualmente y los marca como opcionales.

También puedes declarar modelos de parámetros header y modelos de parámetros cookie opcionales.

Resumen

Puedes usar modelos de Pydantic para declarar parámetros query en FastAPI. 😎

Consejo

Alerta de spoiler: también puedes usar modelos de Pydantic para declarar cookies y headers, pero leerás sobre eso más adelante en el tutorial. 🤫