Modelos Aninhados no Pydantic: Trabalhando com Estruturas Complexas

Cansado de programar?

Cansado(a) de quebrar a cabeça para aprender a programar Python de verdade?

Conheça a melhor e mais completa formação de Python e Django e sinta-se um programador verdadeiramente competente. Além de Python e Django, você também vai aprender Banco de Dados, SQL, HTML, CSS, Javascript, Bootstrap e muito mais!

Quero aprender Python e Django de Verdade! Quero aprender!
Suporte

Tire suas dúvidas diretamente com o professor

Suporte

Projetos práticos voltados para o mercado de trabalho

Suporte

Formação moderna com foco na prática profissional

Download do Artigo

Atualizado para Pydantic V2 (Janeiro 2025)
Modelos aninhados, listas, dicionários, JSON complexo, validação recursiva.

Salve salve Pythonista :wave:

No desenvolvimento de aplicações Python, a manipulação de estruturas de dados complexas pode ser desafiadora.

Com o Pydantic v2, a tarefa de validação e modelagem torna-se mais intuitiva.

Este artigo foca nos modelos aninhados, que permitem representar relações entre dados em Python.

Vamos explorar como o Pydantic lida com listas, dicionários e estruturas JSON complexas.

Além disso, veremos como converter modelos aninhados em dicionários e JSON, essencial para transferências de dados.

Vá Direto ao Assunto…

Representando relações entre dados

O Pydantic permite a construção de modelos aninhados, ou seja, modelos que contêm outros modelos como campos.

Esta função é útil para representar estruturas hierárquicas.

Veja como criar um modelo aninhado simples:

1
2
3
4
5
6
7
8
9
10
from pydantic import BaseModel

class Endereco(BaseModel):
    rua: str
    cidade: str

class Usuario(BaseModel):
    nome: str
    email: str
    endereco: Endereco

Neste exemplo, Usuario possui um campo endereco do tipo Endereco.

Isso estabelece uma relação entre Usuario e seu endereço.

Validação de listas e dicionários

O Pydantic também lida bem com coleções de dados.

Podemos validar listas e dicionários de modelos aninhados facilmente.

Veja um exemplo com listas:

1
2
3
4
5
6
7
class Pedido(BaseModel):
    id_pedido: int
    descricao: str

class Cliente(BaseModel):
    nome: str
    pedidos: list[Pedido]

Aqui, Cliente tem uma lista de pedidos, cada um representado pelo modelo Pedido.

Vamos ver como instanciar e validar:

1
2
3
4
pedido1 = Pedido(id_pedido=1, descricao="Pedido 1")
pedido2 = Pedido(id_pedido=2, descricao="Pedido 2")
cliente = Cliente(nome="Alice", pedidos=[pedido1, pedido2])
print(cliente)

E a saída será:

1
nome='Alice' pedidos=[Pedido(id_pedido=1, descricao='Pedido 1'), Pedido(id_pedido=2, descricao='Pedido 2')]

Essa abordagem promove organização e clareza no código, especialmente com estruturas JSON complexas em APIs.

:package: Modelos complexos na prática: Estou usando Pydantic para estruturar dados no DevBook, uma plataforma que gera ebooks técnicos com IA. Syntax highlighting perfeito, infográficos automáticos e exportação em PDF profissional. Vale conferir!

Validando estruturas JSON complexas

Estruturas JSON complexas são comuns ao lidar com APIs.

O Pydantic facilita a validação e manipulação dessas estruturas.

Veja como usar modelos para validar um JSON complexo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import json

dados_json = '''
{
    "nome": "Carlos",
    "email": "[email protected]",
    "endereco": {
        "rua": "Rua das Flores",
        "cidade": "São Paulo"
    }
}
'''

dados = json.loads(dados_json)
usuario = Usuario(**dados)
print(usuario)

E a saída será:

1
nome='Carlos' email='[email protected]' endereco=Endereco(rua='Rua das Flores', cidade='São Paulo')

Neste exemplo, o JSON é convertido em um modelo Usuario, que é validado automaticamente.

Antes de continuar… Está curtindo esse conteúdo? :thumbsup:

Que tal receber 30 dias de conteúdo direto na sua Caixa de Entrada?

Sua assinatura não pôde ser validada.
Você fez sua assinatura com sucesso.

Assine as PyDicas e receba 30 dias do melhor conteúdo Python na sua Caixa de Entrada: direto e sem enrolação!

Conversão de modelos em dicionários e JSON

O Pydantic permite converter modelos em dicionários e JSON facilmente.

Isso é útil para exportar dados de forma estruturada.

Conversão para dicionários

Usando o método model_dump, é possível converter para dicionário:

1
2
usuario_dict = usuario.model_dump()
print(usuario_dict)

A saída será:

1
{'nome': 'Carlos', 'email': '[email protected]', 'endereco': {'rua': 'Rua das Flores', 'cidade': 'São Paulo'}}

Conversão para JSON

Com model_dump_json, transformamos para JSON:

1
2
usuario_json = usuario.model_dump_json()
print(usuario_json)

A saída será:

1
{"nome": "Carlos", "email": "[email protected]", "endereco": {"rua": "Rua das Flores", "cidade": "São Paulo"}}

Esses métodos são fundamentais para transferir dados em aplicações web.

Casos Práticos Reais

1. Sistema de E-commerce Completo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
from pydantic import BaseModel, EmailStr, Field
from typing import List, Optional
from decimal import Decimal

class ItemCarrinho(BaseModel):
    produto_id: int
    nome: str
    quantidade: int = Field(gt=0)
    preco_unitario: Decimal
    
    @property
    def subtotal(self) -> Decimal:
        return self.preco_unitario * self.quantidade

class Endereco(BaseModel):
    rua: str
    numero: str
    complemento: Optional[str] = None
    bairro: str
    cidade: str
    estado: str
    cep: str

class Cliente(BaseModel):
    id: int
    nome: str
    email: EmailStr
    cpf: str
    enderecos: List[Endereco]

class Pedido(BaseModel):
    id: int
    cliente: Cliente
    itens: List[ItemCarrinho]
    endereco_entrega: Endereco
    
    @property
    def total(self) -> Decimal:
        return sum(item.subtotal for item in self.itens)

# Uso
pedido_data = {
    "id": 1001,
    "cliente": {
        "id": 5,
        "nome": "Maria Silva",
        "email": "[email protected]",
        "cpf": "12345678900",
        "enderecos": [
            {"rua": "Av. Paulista", "numero": "1000", "bairro": "Bela Vista",
             "cidade": "São Paulo", "estado": "SP", "cep": "01310100"}
        ]
    },
    "itens": [
        {"produto_id": 10, "nome": "Notebook", "quantidade": 1, "preco_unitario": "3500.00"},
        {"produto_id": 20, "nome": "Mouse", "quantidade": 2, "preco_unitario": "50.00"}
    ],
    "endereco_entrega": {"rua": "Av. Paulista", "numero": "1000", "bairro": "Bela Vista",
                          "cidade": "São Paulo", "estado": "SP", "cep": "01310100"}
}

pedido = Pedido(**pedido_data)
print(f"Total do pedido: R$ {pedido.total}")  # R$ 3600.00

2. API de Rede Social

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
from datetime import datetime
from typing import List, Optional

class Usuario(BaseModel):
    id: int
    username: str
    nome_completo: str
    bio: Optional[str] = None

class Comentario(BaseModel):
    id: int
    autor: Usuario
    texto: str
    created_at: datetime
    likes: int = 0

class Post(BaseModel):
    id: int
    autor: Usuario
    titulo: str
    conteudo: str
    tags: List[str]
    comentarios: List[Comentario]
    created_at: datetime
    
    @property
    def total_comentarios(self) -> int:
        return len(self.comentarios)
    
    @property
    def total_likes_comentarios(self) -> int:
        return sum(c.likes for c in self.comentarios)

3. Configuração de Aplicação Multi-Ambiente

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
from pydantic import BaseModel, Field
from typing import Dict, Any

class DatabaseConfig(BaseModel):
    host: str
    port: int = 5432
    database: str
    username: str
    password: str
    pool_size: int = Field(default=10, ge=1, le=100)

class RedisConfig(BaseModel):
    host: str
    port: int = 6379
    db: int = 0

class AppConfig(BaseModel):
    app_name: str
    debug: bool = False
    database: DatabaseConfig
    redis: RedisConfig
    api_keys: Dict[str, str]
    features: Dict[str, bool]

config_data = {
    "app_name": "MyApp",
    "debug": True,
    "database": {
        "host": "localhost",
        "database": "myapp_db",
        "username": "user",
        "password": "secret"
    },
    "redis": {"host": "localhost"},
    "api_keys": {"openai": "sk-xxx", "stripe": "pk-xxx"},
    "features": {"new_ui": True, "beta_feature": False}
}

config = AppConfig(**config_data)

Quando Usar Modelos Complexos

APIs REST com payloads aninhados
Perfeito para request/response bodies complexos

Configurações de aplicação
Validar configs YAML/JSON com múltiplos níveis

Dados de domínio complexos
E-commerce, redes sociais, sistemas financeiros

Integração com ORMs
Mapear relacionamentos SQL (1:N, N:N)

Microserviços
Contratos de dados entre serviços

Quando NÃO Usar

Dados muito profundamente aninhados (>5 níveis)
Dificulta manutenção e debugging

Performance crítica com grandes volumes
Validação tem custo - considere dataclasses

Estruturas completamente dinâmicas
Se não há schema definido, Dict[str, Any] pode ser melhor

Dados muito simples
Overhead desnecessário para estruturas planas

Pydantic vs Outras Abordagens

Critério Pydantic Dataclasses Dict NamedTuple
Validação ✅ Automática ❌ Não ❌ Não ❌ Não
Aninhamento ✅ Excelente ⚠️ Manual ✅ Sim ⚠️ Limitado
JSON ✅ Built-in ⚠️ Manual ✅ Nativo ❌ Não
Performance ⚠️ Média ✅ Rápido ✅ Rápido ✅ Rápido
Type hints ✅ Completo ✅ Completo ❌ Não ✅ Sim
Mutável ✅ Sim ✅ Sim ✅ Sim ❌ Não
Uso ideal APIs/Validação Data classes Flexível Imutáveis

Conclusão

Neste guia sobre Modelos Complexos no Pydantic, você aprendeu:

Modelos aninhados - Models dentro de models
Listas tipadas - List[Model] com validação
Dicionários - Dict com tipos complexos
JSON complexo - Estruturas profundamente aninhadas
Serialização - model_dump() e model_dump_json()

Principais lições:

  • Aninhamento permite estruturas complexas e organizadas
  • Validação recursiva garante consistência em toda estrutura
  • Listas e dicts suportam tipos complexos
  • Perfeito para APIs REST com payloads complexos

Próximos passos:

Começe agora sua Jornada na Programação!

Não deixe para amanhã o sucesso que você pode começar a construir hoje!

#newsletter Olá :wave: Curtiu o artigo? Então faça parte da nossa Newsletter! Privacidade Não se preocupe, respeitamos sua privacidade. Você pode se descadastrar a qualquer momento.