Python Data Persistence - SQLAlchemy

Qualquer banco de dados relacional contém dados em tabelas. A estrutura da tabela define o tipo de dados de atributos que são basicamente de tipos de dados primários que são mapeados para os tipos de dados integrados correspondentes do Python. No entanto, os objetos definidos pelo usuário do Python não podem ser armazenados de forma persistente e recuperados de / para tabelas SQL.

Esta é uma disparidade entre os tipos SQL e as linguagens de programação orientadas a objetos, como Python. SQL não tem tipo de dados equivalente para outros como dict, tuple, list ou qualquer classe definida pelo usuário.

Se você tiver que armazenar um objeto em um banco de dados relacional, seus atributos de instância devem ser desconstruídos em tipos de dados SQL primeiro, antes de executar a consulta INSERT. Por outro lado, os dados recuperados de uma tabela SQL estão em tipos primários. Um objeto Python do tipo desejado terá que ser construído usando para uso em script Python. É aqui que os Mapeadores Relacionais de Objeto são úteis.

Mapeador de relação de objeto (ORM)

A Object Relation Mapper(ORM) é uma interface entre uma classe e uma tabela SQL. Uma classe Python é mapeada para uma determinada tabela no banco de dados, para que a conversão entre o objeto e os tipos SQL seja realizada automaticamente.

A classe Alunos escrita em código Python é mapeada para a tabela Alunos no banco de dados. Como resultado, todas as operações CRUD são feitas chamando os respectivos métodos da classe. Isso elimina a necessidade de executar consultas SQL codificadas em script Python.

A biblioteca ORM, portanto, atua como uma camada de abstração sobre as consultas SQL brutas e pode ajudar no desenvolvimento rápido de aplicativos. SQLAlchemyé um mapeador relacional de objeto popular para Python. Qualquer manipulação do estado do objeto do modelo é sincronizada com sua linha relacionada na tabela do banco de dados.

A biblioteca SQLALchemy inclui ORM API e linguagem de expressão SQL (SQLAlchemy Core) A linguagem de expressão executa construções primitivas do banco de dados relacional diretamente.

ORM é um padrão de uso abstrato e de alto nível construído sobre a linguagem de expressão SQL. Pode-se dizer que ORM é um uso aplicado da Expression Language. Discutiremos a API SQLAlchemy ORM e usaremos o banco de dados SQLite neste tópico.

SQLAlchemy se comunica com vários tipos de bancos de dados por meio de suas respectivas implementações DBAPI usando um sistema de dialeto. Todos os dialetos exigem que um driver DBAPI apropriado seja instalado. Dialetos para os seguintes tipos de bancos de dados estão incluídos -

  • Firebird
  • Microsoft SQL Server
  • MySQL
  • Oracle
  • PostgreSQL
  • SQLite
  • Sybase

A instalação do SQLAlchemy é fácil e direta, usando o utilitário pip.

pip install sqlalchemy

Para verificar se SQLalchemy está instalado corretamente e sua versão, digite o seguinte no prompt do Python -

>>> import sqlalchemy
>>>sqlalchemy.__version__
'1.3.11'

As interações com o banco de dados são feitas através do objeto Engine obtido como um valor de retorno de create_engine() função.

engine =create_engine('sqlite:///mydb.sqlite')

SQLite permite a criação de banco de dados na memória. O mecanismo SQLAlchemy para banco de dados na memória é criado da seguinte maneira -

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

Se você pretende usar o banco de dados MySQL, use seu módulo DB-API - pymysql e o respectivo driver de dialeto.

engine = create_engine('mysql+pymydsql://[email protected]/mydb')

O create_engine tem um argumento echo opcional. Se definido como verdadeiro, as consultas SQL geradas pelo mecanismo serão ecoadas no terminal.

SQLAlchemy contém declarative baseclasse. Ele atua como um catálogo de classes de modelo e tabelas mapeadas.

from sqlalchemy.ext.declarative import declarative_base
base=declarative_base()

A próxima etapa é definir uma classe de modelo. Deve ser derivado do objeto base da classe declarative_base como acima.

Conjunto __tablename__ propriedade para o nome da tabela que você deseja criar no banco de dados. Outros atributos correspondem aos campos. Cada um é um objeto Coluna em SQLAlchemy e seu tipo de dados é de um da lista abaixo -

  • BigInteger
  • Boolean
  • Date
  • DateTime
  • Float
  • Integer
  • Numeric
  • SmallInteger
  • String
  • Text
  • Time

O código a seguir é a classe modelo nomeada como Aluno que é mapeada para a tabela Alunos.

#myclasses.py
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, Numeric
base=declarative_base()
class Student(base):
   __tablename__='Students'
   StudentID=Column(Integer, primary_key=True)
   name=Column(String)
   age=Column(Integer)
   marks=Column(Numeric)

Para criar uma tabela de Alunos com uma estrutura correspondente, execute o método create_all () definido para a classe base.

base.metadata.create_all(engine)

Agora temos que declarar um objeto de nossa classe Student. Todas as transações do banco de dados, como adicionar, excluir ou recuperar dados do banco de dados, etc., são tratadas por um objeto de Sessão.

from sqlalchemy.orm import sessionmaker
Session = sessionmaker(bind=engine)
sessionobj = Session()

Os dados armazenados no objeto Aluno são adicionados fisicamente à tabela subjacente pelo método add () da sessão.

s1 = Student(name='Juhi', age=25, marks=200)
sessionobj.add(s1)
sessionobj.commit()

Aqui está todo o código para adicionar registro na tabela de alunos. À medida que é executado, o log da instrução SQL correspondente é exibido no console.

from sqlalchemy import Column, Integer, String
from sqlalchemy import create_engine
from myclasses import Student, base
engine = create_engine('sqlite:///college.db', echo=True)
base.metadata.create_all(engine)

from sqlalchemy.orm import sessionmaker
Session = sessionmaker(bind=engine)
sessionobj = Session()
s1 = Student(name='Juhi', age=25, marks=200)
sessionobj.add(s1)
sessionobj.commit()

Saída do console

CREATE TABLE "Students" (
   "StudentID" INTEGER NOT NULL,
   name VARCHAR,
   age INTEGER,
   marks NUMERIC,
   PRIMARY KEY ("StudentID")
)
INFO sqlalchemy.engine.base.Engine ()
INFO sqlalchemy.engine.base.Engine COMMIT
INFO sqlalchemy.engine.base.Engine BEGIN (implicit)
INFO sqlalchemy.engine.base.Engine INSERT INTO "Students" (name, age, marks) VALUES (?, ?, ?)
INFO sqlalchemy.engine.base.Engine ('Juhi', 25, 200.0)
INFO sqlalchemy.engine.base.Engine COMMIT

o session object também fornece o método add_all () para inserir mais de um objeto em uma única transação.

sessionobj.add_all([s2,s3,s4,s5])
sessionobj.commit()

Agora que os registros foram adicionados à tabela, gostaríamos de buscar nela exatamente como a consulta SELECT faz. O objeto de sessão possui o método query () para realizar a tarefa. O objeto Query é retornado pelo método query () em nosso modelo de Student.

qry=seesionobj.query(Student)

Use o método get () deste objeto Query para obter o objeto correspondente à chave primária fornecida.

S1=qry.get(1)

Enquanto esta instrução é executada, sua instrução SQL correspondente ecoada no console será a seguinte -

BEGIN (implicit)
SELECT "Students"."StudentID" AS "Students_StudentID", "Students".name AS 
   "Students_name", "Students".age AS "Students_age", 
   "Students".marks AS "Students_marks"
FROM "Students"
WHERE "Products"."Students" = ?
sqlalchemy.engine.base.Engine (1,)

O método query.all () retorna uma lista de todos os objetos que podem ser percorridos usando um loop.

from sqlalchemy import Column, Integer, String, Numeric
from sqlalchemy import create_engine
from myclasses import Student,base
engine = create_engine('sqlite:///college.db', echo=True)
base.metadata.create_all(engine)
from sqlalchemy.orm import sessionmaker
Session = sessionmaker(bind=engine)
sessionobj = Session()
qry=sessionobj.query(Students)
rows=qry.all()
for row in rows:
   print (row)

Atualizar um registro na tabela mapeada é muito fácil. Tudo o que você precisa fazer é buscar um registro usando o método get (), atribuir um novo valor ao atributo desejado e então confirmar as alterações usando o objeto de sessão. Abaixo, mudamos as notas do aluno Juhi para 100.

S1=qry.get(1)
S1.marks=100
sessionobj.commit()

Excluir um registro é tão fácil, excluindo o objeto desejado da sessão.

S1=qry.get(1)
Sessionobj.delete(S1)
sessionobj.commit()