🎯 Exemplo de Validação de Dados com Pydantic

Em poucas palavras

Vamos criar um modelo para representar um usuário, com campos como ID, nome, email, idade e um endereço.


📝 Notas e Desenvolvimento


🔗 Conexões e Contexto


📚 Referências e Fontes

Citações Diretas

📂 Outros Conteúdos Preservados

Exemplo de Validação de Dados com Pydantic (Complemento)

from datetime import date
from typing import Optional, List
from pydantic import BaseModel, Field, EmailStr, ValidationError, validator
 
### 1. Definindo um modelo aninhado para o endereço
 
class Address(BaseModel):
    street: str = Field(..., description="Nome da rua")
    city: str = Field(..., description="Cidade")
    zip_code: str = Field(..., regex=r"^\d{5}(-\d{3})?$", description="CEP no formato XXXXX ou XXXXX-XXX")
 
### 2. Definindo o modelo principal para o usuário
 
class User(BaseModel):
    id: int = Field(..., gt=0, description="ID único do usuário, deve ser maior que 0")
    name: str = Field(..., min_length=2, max_length=50, description="Nome completo do usuário")
    email: EmailStr = Field(..., description="Endereço de e-mail válido")
    age: int = Field(default=18, ge=0, le=120, description="Idade do usuário, entre 0 e 120")
    is_active: bool = Field(default=True, description="Indica se o usuário está ativo")
    signup_date: date = Field(default_factory=date.today, description="Data de cadastro do usuário")
    tags: Optional[List[str]] = Field(None, description="Lista opcional de tags associadas ao usuário")
    address: Address = Field(..., description="Endereço do usuário")
 
    # 3. Exemplo de um validador personalizado para o nome
    @validator('name')
    def name_must_be_capitalized(cls, v):
        if not v[0].isupper():
            raise ValueError('O nome deve começar com uma letra maiúscula')
        return v
 
    class Config:
        # Permite que o modelo seja instanciado com dados que não correspondem exatamente aos tipos,
        # tentando fazer a coerção (ex: "123" para int)
        orm_mode = True
        # Gera um esquema JSON com descrições
        schema_vextra = True
 
### --- Exemplos de Uso ---
 
print("--- Exemplo 1: Dados Válidos ---")
try:
    user_data_valid = {
        "id": 123,
        "name": "Alice Smith",
        "email": "[email protected]",
        "age": 30,
        "is_active": True,
        "address": {
            "street": "Rua das Flores, 100",
            "city": "São Paulo",
            "zip_code": "01000-000"
        }
    }
    user1 = User(**user_data_valid)
    print("Usuário válido criado com sucesso:")
    print(user1.json(indent=2)) # Converte o modelo para JSON
    print(f"Tipo do ID: {type(user1.id)}")
    print(f"Tipo da data de cadastro: {type(user1.signup_date)}")
except ValidationError as e:
    print("Erro de validação:", e.json())
 
print("\n--- Exemplo 2: Dados Inválidos ---")
try:
    user_data_invalid = {
        "id": -5,  # Inválido: gt=0
        "name": "bob", # Inválido: não começa com maiúscula
        "email": "bob.example.com", # Inválido: não é um email válido
        "age": 150, # Inválido: le=120
        "address": {
            "street": "Av. Principal",
            "city": "Rio",
            "zip_code": "123" # Inválido: regex não corresponde
        }
    }
    user2 = User(**user_data_invalid)
    print("Usuário inválido criado com sucesso:", user2)
except ValidationError as e:
    print("Erro de validação (dados inválidos):")
    print(e.json(indent=2))
 
print("\n--- Exemplo 3: Coerção de Tipos e Valores Padrão ---")
try:
    user_data_coercion = {
        "id": "456", # Pydantic vai converter para int
        "name": "Carlos Silva",
        "email": "[email protected]",
        # 'age' e 'is_active' serão usados com seus valores padrão (18 e True)
        "address": {
            "street": "Rua da Paz, 50",
            "city": "Belo Horizonte",
            "zip_code": "30000-000"
        }
    }
    user3 = User(**user_data_coercion)
    print("Usuário com coerção e valores padrão:")
    print(user3.json(indent=2))
    print(f"ID (originalmente string): {user3.id}, Tipo: {type(user3.id)}")
    print(f"Idade (valor padrão): {user3.age}")
 
except ValidationError as e:
    print("Erro de validação:", e.json())
 
print("\n--- Exemplo 4: Acessando dados do modelo ---")
if 'user1' in locals():
    print(f"Nome do usuário 1: {user1.name}")
    print(f"Cidade do usuário 1: {user1.address.city}")
    print(f"Data de cadastro do usuário 1: {user1.signup_date}")

Explicação do Código:

  1. BaseModel: A classe User (e Address) herda de pydantic.BaseModel. Esta é a base para todos os modelos Pydantic.
  2. Type Hints: Cada campo (id, name, email, etc.) tem um type hint (ex: int, str, EmailStr, date, bool, Address). A Pydantic usa esses hints para validar os tipos de dados.
  3. Field: A função pydantic.Field permite adicionar metadados e validações extras aos campos:
    • : Indica que o campo é obrigatório e não tem um valor padrão.
    • gt=0, min_length=2, le=120: Restrições de valor (maior que, comprimento mínimo, menor ou igual a).
    • regex=r"^\d{5}(-\d{3})?$": Validação de formato usando expressões regulares para o CEP.
    • description: Uma descrição que pode ser usada para gerar documentação (ex: OpenAPI/Swagger).
    • default=…: Define um valor padrão para o campo se ele não for fornecido.
    • default_factory=date.today: Define uma função que será chamada para gerar um valor padrão (útil para objetos mutáveis ou datas).
  4. EmailStr: Um tipo especial da Pydantic que valida automaticamente se a string fornecida é um endereço de e-mail válido.
  5. Optional e List: Usados do módulo typing para indicar que tags é uma lista opcional de strings.
  6. Modelos Aninhados: A classe Address é um BaseModel separado e é usada como tipo para o campo address dentro do modelo User, permitindo validação de estruturas de dados complexas.
  7. @validator: Decorador para criar validadores personalizados. No exemplo, name_must_be_capitalized garante que o nome comece com uma letra maiúscula. Se a validação falhar, ele levanta um ValueError.
  8. ValidationError: Quando os dados fornecidos não correspondem às regras de validação do modelo, a Pydantic lança uma ValidationError, que contém detalhes sobre quais campos falharam e por quê.
  9. Coerção de Tipos: A Pydantic tenta converter os dados para o tipo esperado. Por exemplo, se você passar "123" para um campo int, ela tentará convertê-lo.
  10. json(): Um método disponível nos modelos Pydantic para serializar a instância do modelo para uma string JSON.
  11. Config: A classe Config aninhada permite configurar o comportamento do modelo, como orm_mode = True (útil para integrar com ORMs) ou schema_extra = True (para incluir descrições no esquema JSON).

Este exemplo demonstra como a Pydantic simplifica a validação de dados, tornando seu código mais robusto e menos propenso a erros de tipo ou formato.