Modelos Pydantic de FastAPI

Pydantic es la dependencia principal de FastAPI para la validación y serialización de datos. Te permite definir modelos de datos con anotaciones de tipos estándar de Python, y automáticamente realiza validación de datos, conversión de tipos y generación de documentación.


¿Qué es Pydantic?

Pydantic es una librería de validación de datos de Python. Su idea central es:Definir estructuras de datos con anotaciones de tipos de Python, y Pydantic se encarga automáticamente de la validación y conversión.En FastAPI, Pydantic se usa principalmente para:

UsoDescripción
Validación del cuerpo de la solicitudValida automáticamente si los datos JSON enviados por el cliente cumplen con la definición del modelo.
Serialización del cuerpo de la respuestaConvierte automáticamente los datos del modelo a respuestas JSON.
Documentación automáticaLos campos, tipos y reglas de validación del modelo aparecen automáticamente en la documentación de la API.
Soporte del editorLos atributos del modelo tienen autocompletado completo en el editor.

Definir modelos Pydantic

Crea una clase que herede deBaseModely declara los campos usando tipos estándar de Python:

Ejemplo

from pydantic import BaseModel


class Item(BaseModel):
    name: str               # Obligatorio: nombre del producto
    description: str | None = None  # Opcional: descripción del producto
    price: float            # Obligatorio: precio del producto
    tax: float | None = None        # Opcional: impuesto

Si un campo es obligatorio depende de si tiene un valor predeterminado:

CampoDeclaración¿Es obligatorio?
namename: strObligatorio
descriptiondescription: str | None = NoneOpcional
priceprice: floatObligatorio
taxtax: float | None = NoneOpcional

Usar modelos Pydantic

Como cuerpo de la solicitud

El uso más común es declarar el modelo como parámetro de una función de operación de ruta:

Ejemplo

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None


@app.post("/items/")
async def create_item(item: Item):
    # FastAPI valida automáticamente el cuerpo de la solicitud y, si pasa la validación, lo asigna al parámetro item
    return item

Acceder y manipular datos del modelo

Ejemplo

@app.post("/items/")
async def create_item(item: Item):
    # Acceder a los atributos del modelo
    print(item.name)       # Acceder directamente a los atributos
    print(item.price)      # El editor ofrece autocompletado

    # Serializar a diccionario
    item_dict = item.model_dump()
    print(item_dict)       # {"name": "Foo", "description": None, "price": 45.2, "tax": None}

    # Serializar a cadena JSON
    item_json = item.model_dump_json()
    print(item_json)       # '{"name":"Foo","description":null,"price":45.2,"tax":null}'

    return item_dict

Pydantic v2 usamodel_dump()ymodel_dump_json()en lugar dedict()yjson()método. El nuevo método tiene mejor rendimiento (implementado en Rust).


Ejemplo de validación del modelo

Cuando los datos enviados por el cliente no cumplen con la definición del modelo, FastAPI devuelve errores de validación detallados:

Ejemplo

# El cliente envió datos a los que faltan campos obligatorios
POST /items/
{
    "description": "Faltan name y price"
}

# FastAPI devuelve el error de validación
{
    "detail": [
        {
            "type": "missing",
            "loc": ["body", "name"],
            "msg": "Field required",
            "input": {"description": "Faltan name y price"}
        },
        {
            "type": "missing",
            "loc": ["body", "price"],
            "msg": "Field required",
            "input": {"description": "Faltan name y price"}
        }
    ]
}

Si se envían datos con tipos incorrectos:

// price 应该是数字,但传了字符串
{
    "name": "Foo",
    "price": "not a number"
}

// FastAPI 返回的错误
{
    "detail": [
        {
            "type": "float_parsing",
            "loc": ["body", "price"],
            "msg": "Input should be a valid number, unable to parse string as a number",
            "input": "not a number"
        }
    ]
}

Métodos comunes de Pydantic v2

Métodov2 (recomendado)v1 (obsoleto)Descripción
Serializar a diccionarioitem.model_dump()item.dict()Convierte el modelo a un diccionario de Python
Serializar a JSONitem.model_dump_json()item.json()Convierte el modelo a una cadena JSON
Crear desde diccionarioItem.model_validate(data)Item.parse_obj(data)Crea y valida el modelo desde un diccionario
Crear desde JSONItem.model_validate_json(json_str)Item.parse_raw(json_str)Crea el modelo desde una cadena JSON
Obtener JSON SchemaItem.model_json_schema()Item.schema()Obtiene el JSON Schema del modelo

Configuración del modelo (model_config)

Pydantic v2 usamodel_configen lugar delConfigclase interna:

Ejemplo

from pydantic import BaseModel, ConfigDict


class Item(BaseModel):
    name: str
    price: float

    # Forma de configuración en Pydantic v2
    model_config = ConfigDict(
        json_schema_extra={  # Mostrar ejemplos en la documentación de la API
            "examples": [
                {
                    "name": "Foo",
                    "price": 35.4
                }
            ]
        }
    )

En Pydantic v2,orm_mode = Truese ha cambiado afrom_attributes = True,schema_extrase ha cambiado ajson_schema_extra,allow_population_by_field_namese ha cambiado apopulate_by_name。


Herencia de modelos

Los modelos Pydantic admiten herencia, lo que permite crear fácilmente modelos de entrada y de salida:

Ejemplo

from pydantic import BaseModel, EmailStr


# Modelo base
class UserBase(BaseModel):
    username: str       # Obligatorio
    email: EmailStr     # Obligatorio, valida automáticamente el formato del correo
    full_name: str | None = None  # Opcional


# Modelo de entrada al crear un usuario (incluye contraseña)
class UserCreate(UserBase):
    password: str       # Obligatorio


# Modelo de salida al devolver información del usuario (no incluye contraseña)
class UserOut(UserBase):
    id: int             # Generado por el servidor


# Ejemplo de uso
@app.post("/users/", response_model=UserOut)
async def create_user(user: UserCreate):
    # La función recibe UserCreate (con contraseña), pero la respuesta usa UserOut (sin contraseña)
    # Así la contraseña no aparece en la respuesta de la API
    return {"id": 1, **user.model_dump(exclude={"password"})}

Usar modelos de entrada y salida diferentes es una práctica importante para proteger datos sensibles. Nunca devuelvas campos sensibles como contraseñas en las respuestas de la API.


Resumen

Puntos clave de los modelos Pydantic:

  • UsaBaseModelpara definir modelos de datos, declara los campos con tipos estándar de Python
  • Los campos con valor predeterminado son opcionales; los que no tienen valor predeterminado son obligatorios.
  • v2 usamodel_dump()、model_validate()etc., métodos nuevos
  • Crea diferentes modelos de entrada/salida mediante herencia de modelos para proteger datos sensibles.
  • Toda la validación y la documentación son automáticas; solo necesitas declarar los tipos una vez.
Otras extensiones