Introdução
SQLAlchemy constitui um dos frameworks ORM (Object-Relational Mapping) mais utilizados no ecossistema Python, oferecendo mecanismos eficientes e flexíveis para interação com bancos de dados relacionais. Este material apresenta uma abordagem detalhada sobre as funcionalidades essenciais do SQLAlchemy ORM.
Sumário
- Instalação do SQLAlchemy
- Conceitos Fundamentais
- Estabelecendo Conexão com Banco de Dados
- Definindo Modelos de Dados
- Criando Tabelas no Banco de Dados
- Operações CRUD Básicas
- Consultas ao Banco de Dados
- Manipulação de Relacionamentos
- Gerenciamento de Transações
- Boas Práticas
Instalação
pip install sqlalchemy
Para conexão com bancos de dados específicos, é necessário instalar os drivers correspondentes:
# PostgreSQL
pip install psycopg2-binary
# MySQL
pip install mysql-connector-python
# SQLite (Já incluído na biblioteca padrão Python)
Conceiots Fundamentais
- Engine: Motor responsável pela comunicação com o banco de dados
- Session: Sessão que gerencia todas as operações de persistência
- Model: Classe que representa uma tabela no banco de dados
- Query: Objeto utilizado para construir e executar consultas
Estabelecendo Conexão com Banco de Dados
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
# Criando o motor de conexão
# Exemplo com SQLite
engine = create_engine('sqlite:///exemplo.db', echo=True)
# Exemplo com PostgreSQL
# engine = create_engine('postgresql://usuario:senha@localhost:5432/meubanco')
# Exemplo com MySQL
# engine = create_engine('mysql+mysqlconnector://usuario:senha@localhost:3306/meubanco')
# Criando a fábrica de sessões
SessionFactory = sessionmaker(autocommit=False, autoflush=False, bind=engine)
# Instanciando uma sessão
sessao = SessionFactory()
Definindo Modelos de Dados
from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import relationship, declarative_base
# Criando a classe base
Base = declarative_base()
class Cliente(Base):
__tablename__ = 'clientes'
id = Column(Integer, primary_key=True, index=True)
nome = Column(String(50), nullable=False)
email = Column(String(100), unique=True, index=True)
# Definindo relacionamento um-para-muitos
pedidos = relationship("Pedido", back_populates="cliente")
class Pedido(Base):
__tablename__ = 'pedidos'
id = Column(Integer, primary_key=True, index=True)
titulo = Column(String(100), nullable=False)
descricao = Column(String(500))
cliente_id = Column(Integer, ForeignKey('clientes.id'))
# Definindo relacionamento muitos-para-um
cliente = relationship("Cliente", back_populates="pedidos")
# Definindo relacionamento muitos-para-muitos (via tabela associativa)
categorias = relationship("Categoria", secondary="pedido_categorias", back_populates="pedidos")
class Categoria(Base):
__tablename__ = 'categorias'
id = Column(Integer, primary_key=True, index=True)
nome = Column(String(30), unique=True, nullable=False)
pedidos = relationship("Pedido", secondary="pedido_categorias", back_populates="categorias")
# Tabela associativa (para relacionamento muitos-para-muitos)
class PedidoCategoria(Base):
__tablename__ = 'pedido_categorias'
pedido_id = Column(Integer, ForeignKey('pedidos.id'), primary_key=True)
categoria_id = Column(Integer, ForeignKey('categorias.id'), primary_key=True)
Criando Tabelas no Banco de Dados
# Criando todas as tabelas
Base.metadata.create_all(bind=engine)
# Removendo todas as tabelas
# Base.metadata.drop_all(bind=engine)
Operações CRUD Básicas
Inserindo Dados
# Criando um novo cliente
novo_cliente = Cliente(nome="João Silva", email="joao@exemplo.com")
sessao.add(novo_cliente)
sessao.commit()
# Inserção em批量
sessao.add_all([
Cliente(nome="Maria Santos", email="maria@exemplo.com"),
Cliente(nome="Pedro Oliveira", email="pedro@exemplo.com")
])
sessao.commit()
Lendo Dados
# Obtendo todos os clientes
clientes = sessao.query(Cliente).all()
# Obtendo o primeiro cliente
primeiro_cliente = sessao.query(Cliente).first()
# Obtendo cliente por ID
cliente = sessao.query(Cliente).get(1)
Atualizando Dados
# Consultando e atualizando
cliente = sessao.query(Cliente).get(1)
cliente.nome = "João Silva Santos"
sessao.commit()
# Atualização em批量
sessao.query(Cliente).filter(Cliente.nome.like("João%")).update({"nome": "João"}, synchronize_session=False)
sessao.commit()
Excluindo Dados
# Consultando e excluindo
cliente = sessao.query(Cliente).get(1)
sessao.delete(cliente)
sessao.commit()
# Exclusão em批量
sessao.query(Cliente).filter(Cliente.nome == "Maria Santos").delete(synchronize_session=False)
sessao.commit()
Consultas ao Banco de Dados
Consultas Básicas
# Obtendo todos os registros
clientes = sessao.query(Cliente).all()
# Obtendo campos específicos
nomes = sessao.query(Cliente.nome).all()
# Ordenação
clientes = sessao.query(Cliente).order_by(Cliente.nome.desc()).all()
# Limitando resultados
clientes = sessao.query(Cliente).limit(10).all()
# Offset (paginação)
clientes = sessao.query(Cliente).offset(5).limit(10).all()
Filtros em Consultas
from sqlalchemy import or_
# Filtragem por igualdade
cliente = sessao.query(Cliente).filter(Cliente.nome == "João Silva").first()
# LIKE (busca parcial)
clientes = sessao.query(Cliente).filter(Cliente.nome.like("João%")).all()
# IN (busca em lista)
clientes = sessao.query(Cliente).filter(Cliente.nome.in_(["João Silva", "Maria Santos"])).all()
# Múltiplos critérios
clientes = sessao.query(Cliente).filter(
Cliente.nome == "João Silva",
Cliente.email.like("%@exemplo.com")
).all()
# Condição OR
clientes = sessao.query(Cliente).filter(
or_(Cliente.nome == "João Silva", Cliente.nome == "Maria Santos")
).all()
# Diferente de
clientes = sessao.query(Cliente).filter(Cliente.nome != "João Silva").all()
Consultas de Agregação
from sqlalchemy import func
# Contagem
quantidade = sessao.query(Cliente).count()
# Agrupamento e contagem
contagem_pedidos = sessao.query(
Cliente.nome,
func.count(Pedido.id)
).join(Pedido).group_by(Cliente.nome).all()
# Média, soma, etc.
media_id = sessao.query(func.avg(Cliente.id)).scalar()
Consultas com JOIN
# Inner Join
resultados = sessao.query(Cliente, Pedido).join(Pedido).filter(Pedido.titulo.like("%Python%")).all()
# Left Outer Join
resultados = sessao.query(Cliente, Pedido).outerjoin(Pedido).all()
# Join com condição específica
resultados = sessao.query(Cliente, Pedido).join(Pedido, Cliente.id == Pedido.cliente_id).all()
Manipulação de Relacionamentos
# Criando objetos com relacionamentos
cliente = Cliente(nome="Ana Costa", email="ana@exemplo.com")
pedido = Pedido(titulo="Meu Primeiro Pedido", descricao="Olá Mundo!", cliente=cliente)
sessao.add(pedido)
sessao.commit()
# Acessandovia relacionamento
print(f"Pedido '{pedido.titulo}' pertence a {pedido.cliente.nome}")
print(f"Todos os pedidos do cliente {cliente.nome}:")
for p in cliente.pedidos:
print(f" - {p.titulo}")
# Operações em relacionamentos muitos-para-muitos
categoria_python = Categoria(nome="Python")
categoria_banco = Categoria(nome="Banco de Dados")
pedido.categorias.append(categoria_python)
pedido.categorias.append(categoria_banco)
sessao.commit()
print(f"Categorias do pedido '{pedido.titulo}':")
for cat in pedido.categorias:
print(f" - {cat.nome}")
Gerenciamento de Transações
# Commit automático com tratamento de exceções
try:
cliente = Cliente(nome="Cliente Teste", email="teste@exemplo.com")
sessao.add(cliente)
sessao.commit()
except Exception as erro:
sessao.rollback()
print(f"Ocorreu um erro: {erro}")
# Usando gerenciador de contexto
from sqlalchemy.orm import Session
def criar_cliente(sessao: Session, nome: str, email: str):
try:
cliente = Cliente(nome=nome, email=email)
sessao.add(cliente)
sessao.commit()
return cliente
except:
sessao.rollback()
raise
# Transações aninhadas
with sessao.begin_nested():
cliente = Cliente(nome="Cliente Transação", email="transacao@exemplo.com")
sessao.add(cliente)
# Savepoints (pontos de salvamento)
ponto_salvamento = sessao.begin_nested()
try:
cliente = Cliente(nome="Cliente Savepoint", email="savepoint@exemplo.com")
sessao.add(cliente)
ponto_salvamento.commit()
except:
ponto_salvamento.rollback()
Boas Práticas
- Gerenciamento de Sessão: Criar uma nova sessão para cada requisição e fechá-la ao final
- Tratamento de Exceções: Sempre tratar exceções e realizar rollback apropriado das transações
- Carregamento Preguiçoso: Cuiddar com o problema N+1 de consultas, utilizar eager loading para otimização
- Pool de Conexões: Configurar adequadamente o tamanho do pool e timeout de conexões
- Validação de Dados: Validar integridade dos dados na camada de modelo ou aplicação
# Utilizando gerenciador de contexto para sessões
from contextlib import contextmanager
@contextmanager
def obter_sessao():
db = SessionFactory()
try:
yield db
db.commit()
except Exception:
db.rollback()
raise
finally:
db.close()
# Exemplo de uso
with obter_sessao() as db:
cliente = Cliente(nome="Cliente Contexto", email="contexto@exemplo.com")
db.add(cliente)
Considerações Finais
SQLAlchemy ORM oferece um conjunto robusto e flexível de ferramentas para manipulação de banco de dados em Python. Após este material, você deverá ser capaz de:
- Instalar e configurar o SQLAlchemy
- Definir modelos de dados e seus relacionamentos
- Executar operações CRUD básicas
- Construir consultas complexas
- Gerenciar transações no banco de dados
- Aplicar boas práticas no desenvolvimento
SQLAlchemy possui diversas funcionalidades avançadas, como propreidades híbridas, listeners de eventos, e consultas personalizadas, que merecem ser exploradas em estudos posteriores.