Contexto
Analista de dados que toca apenas SQL fica limitado. No mundo real, o dado nasce em sistemas que usam ORM , e entender como ele é persistido importa para consumir bem. Este projeto foi a oportunidade de cruzar o lado da modelagem relacional (que já trabalhei em SQL puro) com o lado da modelagem orientada a objetos.
Problema
Modelar uma instituição financeira simples, clientes, contas, transações, usando classes Python que se comportam como entidades de domínio mas persistem em um banco relacional, com integridade referencial garantida pelo ORM.
Abordagem
- Modelagem do domínio em classes: Cliente, Conta, Transação, com seus atributos e métodos de negócio.
- Mapeamento ORM via SQLAlchemy: declarative base, tipos, FKs, e
relationship()bidirecional. - Sessões e transações: entendimento prático de
session.add(),session.commit(), rollback. - Queries com a API do ORM e comparação com o SQL gerado por trás.
Decisões de modelagem
Escolhas práticas
- Relacionamento bidirecional com
back_populates, navegação ergonômica em ambas direções. - Cascade configurado por relacionamento: deletar cliente deleta suas contas? Decisão explícita, não default.
- Métodos de domínio nas classes:
conta.depositar(valor)em vez de manipular o atributo diretamente. - Sessão como context manager: commit ou rollback garantido, sem vazamento.
Resultado
ORM não é "SQL mais fácil", é uma camada de abstração com trade-offs próprios. Saber quando usar e quando descer para SQL puro é parte do ofício.
O projeto fica como referência viva: quando precisar montar um pipeline que combine modelagem de domínio com persistência relacional, o esqueleto aqui já está testado.
Stack
Aprendizados
O ORM esconde SQL, não substitui o conhecimento dele. Em vários momentos foi necessário olhar o SQL gerado pelo SQLAlchemy para entender por que uma query estava lenta ou retornando algo inesperado. Conhecimento de SQL puro é pré-requisito para usar bem o ORM, não opcional.
Aprendi também que relacionamento bidirecional é uma decisão de design, não automática.
Ter cliente.contas E conta.cliente facilita o código que consome, mas exige
configurar o back_populates consistentemente, e sem isso, dá pra ter inconsistência de estado.