Utilizando SQLAlchemy ORM para Operações de Banco de Dados em Python

Instalação

Para instalar o SQLAlchemy, execute o seguinte comando:

pip install sqlalchemy

Se precisar se conectar a um banco de dados específico, instale o driver correspondente:

# Para PostgreSQL
pip install psycopg2-binary

# Para MySQL
pip install mysql-connector-python

# Para SQLite, já está incluído na biblioteca padrão do Python.

Conceitos Fundamentais

Os componentes principais do SQLAlchemy ORM incluem:

  • Motor (Engine): Responsável pela comunicação com o banco de dados.
  • Sessão (Session): Gerencia as operações de persistência.
  • Modelo (Model): Classes que mapeiam tabelas no banco de dados.
  • Consulta (Query): Objeto para construir e executar consultas.

Conexão com o Banco de Dados

Crie uma instância de motor e uma fábrica de sessões:

from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

# Exemplo com SQLite
motor = create_engine('sqlite:///meu_banco.db', echo=False)

# Para PostgreSQL (descomente e ajuste conforme necessário)
# motor = create_engine('postgresql://usuario:senha@localhost:5432/meu_banco')

# Para MySQL
# motor = create_engine('mysql+mysqlconnector://usuario:senha@localhost:3306/meu_banco')

FabricaSessao = sessionmaker(autocommit=False, autoflush=False, bind=motor)
sessao = FabricaSessao()

Definição de Modelos de Dados

Utilize a base declarativa para definir os modelos:

from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import relationship, declarative_base

Base = declarative_base()

class Cliente(Base):
    __tablename__ = 'clientes'
    
    id_cliente = Column(Integer, primary_key=True, index=True)
    nome_completo = Column(String(50), nullable=False)
    email_contato = Column(String(100), unique=True, index=True)
    
    # Relação um-para-muitos
    publicacoes = relationship("Publicacao", back_populates="autor")

class Publicacao(Base):
    __tablename__ = 'publicacoes'
    
    id_publicacao = Column(Integer, primary_key=True, index=True)
    titulo = Column(String(100), nullable=False)
    corpo = Column(String(500))
    autor_id = Column(Integer, ForeignKey('clientes.id_cliente'))
    
    # Relação muitos-para-um
    autor = relationship("Cliente", back_populates="publicacoes")
    
    # Relação muitos-para-muitos via tabela associativa
    etiquetas = relationship("Etiqueta", secondary="publicacao_etiquetas", back_populates="publicacoes")

class Etiqueta(Base):
    __tablename__ = 'etiquetas'
    
    id_etiqueta = Column(Integer, primary_key=True, index=True)
    rotulo = Column(String(30), unique=True, nullable=False)
    
    publicacoes = relationship("Publicacao", secondary="publicacao_etiquetas", back_populates="etiquetas")

class PublicacaoEtiqueta(Base):
    __tablename__ = 'publicacao_etiquetas'
    
    publicacao_id = Column(Integer, ForeignKey('publicacoes.id_publicacao'), primary_key=True)
    etiqueta_id = Column(Integer, ForeignKey('etiquetas.id_etiqueta'), primary_key=True)

Criação de Tabelas

Execute a criação das tabelas no banco de dados:

# Criar todas as tabelas
Base.metadata.create_all(bind=motor)

# Para remover todas as tabelas (use com cautela)
# Base.metadata.drop_all(bind=motor)

Operações CRUD Básicas

Criação de Dados

# Adicionar um novo cliente
novo_cliente = Cliente(nome_completo="Ana Silva", email_contato="ana@exemplo.com")
sessao.add(novo_cliente)
sessao.commit()

# Adicionar múltiplos registros
sessao.add_all([
    Cliente(nome_completo="Carlos Oliveira", email_contato="carlos@exemplo.com"),
    Cliente(nome_completo="Maria Souza", email_contato="maria@exemplo.com")
])
sessao.commit()

Leitura de Dados

# Obter todos os clientes
todos_clientes = sessao.query(Cliente).all()

# Obter o primeiro cliente
primeiro_cliente = sessao.query(Cliente).first()

# Obter cliente por ID
cliente = sessao.query(Cliente).get(1)

Atualização de Dados

# Atualizar um registro existente
cliente = sessao.query(Cliente).get(1)
cliente.nome_completo = "Ana Silva Santos"
sessao.commit()

# Atualização em massa
sessao.query(Cliente).filter(Cliente.nome_completo.like("Ana%")).update({"nome_completo": "Ana S."}, synchronize_session=False)
sessao.commit()

Exclusão de Dados

# Excluir um registro
cliente = sessao.query(Cliente).get(1)
sessao.delete(cliente)
sessao.commit()

# Exclusão em massa
sessao.query(Cliente).filter(Cliente.nome_completo == "Carlos Oliveira").delete(synchronize_session=False)
sessao.commit()

Consultas Avançadas

Consultas Básicas

# Listar todos os registros
clientes = sessao.query(Cliente).all()

# Selecionar colunas específicas
nomes = sessao.query(Cliente.nome_completo).all()

# Ordenação
clientes_ordenados = sessao.query(Cliente).order_by(Cliente.nome_completo.desc()).all()

# Limitar resultados
clientes_limitados = sessao.query(Cliente).limit(5).all()

# Usar offset
clientes_com_offset = sessao.query(Cliente).offset(3).limit(5).all()

Filtros

from sqlalchemy import or_

# Filtro por igualdade
cliente = sessao.query(Cliente).filter(Cliente.nome_completo == "Ana Silva").first()

# Filtro com like
clientes = sessao.query(Cliente).filter(Cliente.nome_completo.like("%Silva%")).all()

# Filtro com IN
clientes = sessao.query(Cliente).filter(Cliente.nome_completo.in_(["Ana Silva", "Maria Souza"])).all()

# Múltiplas condições
clientes = sessao.query(Cliente).filter(
    Cliente.nome_completo == "Ana Silva",
    Cliente.email_contato.like("%@exemplo.com")
).all()

# Condição OR
clientes = sessao.query(Cliente).filter(
    or_(Cliente.nome_completo == "Ana Silva", Cliente.nome_completo == "Maria Souza")
).all()

# Diferente
clientes = sessao.query(Cliente).filter(Cliente.nome_completo != "Ana Silva").all()

Agregações

from sqlalchemy import func

# Contagem
total_clientes = sessao.query(Cliente).count()

# Contagem por grupo com junção
contagem_publicacoes = sessao.query(
    Cliente.nome_completo,
    func.count(Publicacao.id_publicacao)
).join(Publicacao).group_by(Cliente.nome_completo).all()

# Média
media_ids = sessao.query(func.avg(Cliente.id_cliente)).scalar()

Junções

# Junção interna
resultados = sessao.query(Cliente, Publicacao).join(Publicacao).filter(Publicacao.titulo.like("%Python%")).all()

# Junção externa esquerda
resultados = sessao.query(Cliente, Publicacao).outerjoin(Publicacao).all()

# Condição de junção explícita
resultados = sessao.query(Cliente, Publicacao).join(Publicacao, Cliente.id_cliente == Publicacao.autor_id).all()

Operações com Relacionamentos

# Criar objetos relacionados
cliente = Cliente(nome_completo="Pedro Lima", email_contato="pedro@exemplo.com")
publicacao = Publicacao(titulo="Meu primeiro artigo", corpo="Conteúdo aqui", autor=cliente)
sessao.add(publicacao)
sessao.commit()

# Acessar relacionamentos
print(f"A publicação '{publicacao.titulo}' foi escrita por {publicacao.autor.nome_completo}")
print(f"Publicações do cliente {cliente.nome_completo}:")
for pub in cliente.publicacoes:
    print(f"  - {pub.titulo}")

# Manipular relacionamento muitos-para-muitos
etiqueta_python = Etiqueta(rotulo="Python")
etiqueta_sqlalchemy = Etiqueta(rotulo="SQLAlchemy")

publicacao.etiquetas.append(etiqueta_python)
publicacao.etiquetas.append(etiqueta_sqlalchemy)
sessao.commit()

print(f"Etiquetas da publicação '{publicacao.titulo}':")
for etq in publicacao.etiquetas:
    print(f"  - {etq.rotulo}")

Gerenciamento de Transações

# Transação com tratamento de erros
try:
    cliente = Cliente(nome_completo="Teste", email_contato="teste@exemplo.com")
    sessao.add(cliente)
    sessao.commit()
except Exception as e:
    sessao.rollback()
    print(f"Erro ocorrido: {e}")

# Função com gerenciamento de sessão
from sqlalchemy.orm import Session

def criar_cliente(sessao: Session, nome: str, email: str):
    try:
        cliente = Cliente(nome_completo=nome, email_contato=email)
        sessao.add(cliente)
        sessao.commit()
        return cliente
    except:
        sessao.rollback()
        raise

# Transação aninhada
with sessao.begin_nested():
    cliente = Cliente(nome_completo="Transação Aninhada", email_contato="aninhado@exemplo.com")
    sessao.add(cliente)

# Savepoint
ponto_salvo = sessao.begin_nested()
try:
    cliente = Cliente(nome_completo="Savepoint", email_contato="savepoint@exemplo.com")
    sessao.add(cliente)
    ponto_salvo.commit()
except:
    ponto_salvo.rollback()

Boas Práticas

  • Gerenciamento de Sessão: Crie uma nova sessão para cada unidade de trabalho e feche-a após o uso.
  • Traatmento de Exceções: Sempre trate exceções e realize rollback quando necessário.
  • Carregamento Preguiçoso: Evite problemas N+1 utilizando carrgeamento ansioso (eager loading) quando apropriado.
  • Pool de Conexões: Configure adequadamente o tamenho e timeout do pool de conexões.
  • Validação de Dados: Implemente validações no nível do modelo ou da aplicação para garantir integridade.
# Gerenciamento de sessão com context manager
from contextlib import contextmanager

@contextmanager
def obter_sessao():
    db = FabricaSessao()
    try:
        yield db
        db.commit()
    except Exception:
        db.rollback()
        raise
    finally:
        db.close()

# Exemplo de uso
with obter_sessao() as db:
    cliente = Cliente(nome_completo="Contexto", email_contato="contexto@exemplo.com")
    db.add(cliente)

Tags: SQLAlchemy Python ORM database SQL

Publicado em 6-14 01:38 por Thomas