Gerenciamento Pythonico de Bancos de Dados com SQLAlchemy

A icônica biblioteca Python para lidar com qualquer interação de banco de dados concebível.

Todd Birchard Blocked Unblock Seguir Seguindo 9 de janeiro

Algo que tomamos como garantido até agora em Hackers e Slackers é uma biblioteca que a maioria dos profissionais de dados aceitou como um padrão indiscutível: o SQLAlchemy .

No passado, cobrimos o gerenciamento de conexões de banco de dados e consultas usando bibliotecas como PyMySQL e Psycopg2, as quais fazem um excelente trabalho de interação com bancos de dados, da mesma forma que esperávamos. A natureza de abrir / fechar conexões de banco de dados e trabalhar com cursores não mudou muito nas últimas décadas (quase a vida útil dos próprios bancos de dados relacionais). Enquanto boilerplate é chato, pelo menos, permaneceu consistente, pode-se descobrir. Esse pode ter sido o caso, mas o boom filosófico dos frameworks do MVC há quase uma década desencadeou o surgimento de popularidade dos ORMs. Enquanto o mundo cantava elogios à programação orientada a objetos, conter funcionalidades orientadas a banco de dados dentro de objetos deve ter sido um sonho molhado.

A única coisa chocante sobre a popularidade do SQLAlchemy é o outro lado: a contingência daqueles que funcionam sem o SQLAlchemy como parte de sua pilha regular. Se isso deriva do desconhecimento ou da relutância ativa em mudar, as equipes de dados que usam o Python sem um ORM adequado são surpreendentemente prevalentes. É fácil esquecer a realidade da força de trabalho quando nossas interações com outros profissionais vêm principalmente de blogs publicados por quem está no topo de seu campo.

Eu percebo que a atitude “é assim que sempre fizemos” é um clichê sem escassez de comentários. Contos de adotar novas práticas (relativamente falando) dominam os blogs do Vale do Silício todos os dias – é a maneira pela qual isso se manifesta, no entanto, que me pega desprevenida. Nesse caso, a resistência a uma única biblioteca Python pode lançar luz sobre um modelo mental assustador que tem implicações para cima e para baixo na pilha de uma corporação.

Colocando o 'M' no MVC

Estruturas que reforçam um Model-View-Controller mantiveram um consenso indiscutível por tempo suficiente: nenhum de nós precisa recapitular porque a criação de aplicativos dessa maneira é inequivocamente correta. Para entender por que o side-stepping de um ORM é tão significativo, vamos nos lembrar do que o ORM significa:

O mapeamento objeto-relacional, comumente chamado de abreviação ORM, é uma técnica que conecta os objetos ricos de um aplicativo a tabelas em um sistema de gerenciamento de banco de dados relacional. Usando o ORM, as propriedades e os relacionamentos dos objetos em um aplicativo podem ser facilmente armazenados e recuperados de um banco de dados sem escrever instruções SQL diretamente e com menos código de acesso geral ao banco de dados.

Registro Ativo

ORMs nos permitem interagir com bancos de dados simplesmente modificando objetos no código (como classes) em vez de gerar consultas SQL manualmente para cada interação do banco de dados. Saltar do código do aplicativo para o SQL é uma grande alternância de contexto , e quanto mais interações introduzimos, mais fora de controle nosso aplicativo se torna.

Para ilustrar a alternativa a isso usando modelos, usarei um exemplo oferecido pelo Flask-SQLAlchemy . Digamos que temos uma tabela de usuários que contém colunas para id, nome de usuário e email. Um modelo para tal tabela seria assim:

 class User (db.Model): 
id = db.Column (db.Integer, primary_key = True)
nome de usuário = db.Column (db.String (80), unique = True, nullable = False)
email = db.Column (db.String (120), unique = True, nullable = False)
 def __repr __ (self): 
return '<User% r>'% self.username

O 'modelo' é um objeto que representa a estrutura de uma única entrada em nossa tabela. Uma vez que nosso modelo existe, isso é tudo o que é necessário para criar uma entrada:

 newuser = User(username='admin', email=' [email protected] ') 

Essa é uma única linha de código legível sem escrever uma única linha de SQL. Compare isso com a alternativa, que seria usar o Psycopg2:

 query = "INSERT INTO usuários VALORES username = 'admin', email='admin@example.com ';" 
 def query_function (consulta): 
"" "Executa uma consulta de banco de dados." ""
experimentar:
conn = psycopg2.connect (
user = config.username,
password = config.password,
host = config.host,
port = config.port,
database = config.database)
com conn.cursor () como cur:
cur.execute (consulta)
cur.close ()
conn.close ()
exceto exceção como e:
print (e)

query_function (consulta)

Claro, query_function() só precisa ser definido uma vez, mas compare a legibilidade de usar um modelo para o seguinte:

 query = "INSERT INTO usuários VALORES username = 'admin', email='admin@example.com ';" 
 query_function (consulta) 

Apesar de alcançar o mesmo efeito, este último é muito menos legível ou passível de manutenção pelos seres humanos. Construir um aplicativo em torno de consultas de string brutas pode rapidamente se tornar um pesadelo.

Integração com outras bibliotecas de dados

Quando se trata de padrões dourados de bibliotecas Python, não há mais por excelência em análise de dados do que os Pandas. O emparelhamento de Pandas e SQLAlchemy é padrão para o ponto em que o Pandas possui integrações integradas para interagir com dados do SQLAlchemy. Aqui está o que é preciso para transformar uma tabela de banco de dados em um Dataframe Pandas com SQLAlchemy como nosso conector:

 df = pd.read_sql(session.query(Table).filter(User.id == 2).statement,session.bind) 

Mais uma vez, uma única linha de código Python!

Escrevendo consultas puramente em Python

Até agora, usando o SQLAlchemy, não precisávamos escrever uma única linha de SQL: até onde poderíamos fazer isso? Tanto quanto nós queremos, na verdade. O SQLAlchemy contém o que eles chamaram de construção de consulta baseada em função, o que significa que podemos construir praticamente qualquer consulta SQL concebível exclusivamente em Python usando os métodos que nos são oferecidos. Por exemplo, aqui está uma consulta de atualização:

 stmt = users.update().values(fullname="Fullname: " + users.c.name) conn.execute(stmt) 

Verifique a referência completa para ver o que quero dizer . Toda consulta que você precisou escrever: está tudo lá. Tudo isso.

Gerenciamento Simples de Conexões

Vendo como todos nós agora concordamos que o SQLAlchemy é benéfico para o nosso fluxo de trabalho, vamos visitar a primeira etapa e ver como é simples gerenciar as conexões. As duas palavras-chave para lembrar aqui são motores e sessões .

O motor

Um mecanismo no SQLAlchemy é meramente um objeto básico que representa nosso banco de dados. Tornar o SQLAlchemy ciente de nosso banco de dados é tão simples quanto essas duas linhas:

 from sqlalchemy import create_engine 
 engine = create_engine('sqlite:///:memory:', echo=True) 

O mecanismo pode interagir com nosso banco de dados aceitando um URI simples. Uma vez que o engine existe, poderíamos, em teoria, usar o motor exclusivamente por meio de funções como engine.connect() e engine.execute() .

Sessões

Para interagir com nosso banco de dados de maneira Pythonica através do ORM, precisaremos criar uma sessão a partir do mecanismo que acabamos de declarar. Assim nosso código se expande:

 from sqlalchemy import create_engine 
from sqlalchemy.orm import sessionmaker
 engine = create_engine('sqlite:///:memory:', echo=True) 
Session = sessionmaker(bind=engine)

É tudo que é preciso! Agora, como antes, podemos usar o ORM do SQLAlchemy e funções internas para fazer interações simples:

 new_user = User(name='todd', 
fullname='Todd Hacker',
password='toddspassword')
session.add(new_user)

Sugestões para viagem

Vale a pena mencionar que o SQLAlchemy trabalha com quase todos os tipos de banco de dados, e o faz aproveitando a biblioteca Python base para o respectivo tipo de banco de dados. Por exemplo, provavelmente parece de fora que passamos algum tempo cagando no Psycopg2. Pelo contrário, quando o SQLAlchemy se conecta a um banco de dados do Postgres, ele está usando a biblioteca do Psycopg2 para gerenciar o boilerplate para nós. O mesmo vale para todos os outros tipos de bancos de dados relacionais, juntamente com suas bibliotecas padrão.

muitas outras razões pelas quais o SQLAlchemy é benéfico ao ponto de ser considerado fundamental para os fluxos de trabalho de análise de dados. O ponto crítico a ser feito aqui é que deixar o SQLAlchemy fora de qualquer fluxo de trabalho de dados só prejudica a pessoa que está escrevendo o código ou, mais importante, todos aqueles que vêm depois.

Texto original em inglês.