Python 数据持久化 - SQLAlchemy

任何关系数据库都将数据保存在表中。 表结构定义了属性的数据类型,这些属性基本上只是初级数据类型,它们映射到对应的Python内置数据类型。 但是,Python 的用户定义对象不能持久存储到 SQL 表或从 SQL 表检索。

这是 SQL 类型和面向对象的编程语言(如 Python)之间的差异。 SQL 没有与其他数据类型等效的数据类型,例如字典、元组、列表或任何用户定义的类。

如果你必须在关系数据库中存储一个对象,在执行 INSERT 查询之前,应该先将它的实例属性解构为 SQL 数据类型。 另一方面,从 SQL 表中检索的数据是主要类型。 必须通过在 Python 脚本中使用 for 来构造所需类型的 Python 对象。 这就是对象关系映射器的用武之地。


对象关系映射器 (ORM)

对象关系映射器 (ORM) 是类和 SQL 表之间的接口。 一个Python类映射到数据库中的某个表,从而自动进行对象类型和SQL类型之间的转换。

用 Python 代码编写的 Students 类映射到数据库中的 Students 表。 因此,所有 CRUD 操作都是通过调用类的相应方法来完成的。 这消除了在 Python 脚本中执行硬编码 SQL 查询的需要。

ORM 库因此充当原始 SQL 查询的抽象层,有助于快速应用程序开发。 SQLAlchemy 是一种流行的 Python 对象关系映射器。 对模型对象状态的任何操作都与其在数据库表中的相关行同步。

SQLALchemy 库包括 ORM API 和 SQL 表达式语言(SQLAlchemy 核心)。 表达式语言直接执行关系数据库的原始构造。

ORM 是一种构建在 SQL 表达式语言之上的高级抽象使用模式。 可以说ORM是表达式语言的一种应用用法。 我们将讨论 SQLAlchemy ORM API 并在本主题中使用 SQLite 数据库。

SQLAlchemy 使用方言系统通过各自的 DBAPI 实现与各种类型的数据库进行通信。 所有方言都需要安装适当的 DBAPI 驱动程序。 包括以下类型数据库的方言 −

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

使用 pip 实用程序安装 SQLAlchemy 简单直接。

pip install sqlalchemy

要检查 SQLalchemy 是否已正确安装及其版本,请在 Python 提示符下输入以下内容 −

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

与数据库的交互是通过作为 create_engine() 函数的返回值获得的 Engine 对象完成的。

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

SQLite 允许创建内存数据库。 用于内存数据库的 SQLAlchemy 引擎创建如下 −

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

如果您打算改用 MySQL 数据库,请使用其 DB-API 模块 – pymysql 和相应的方言驱动程序。

engine = create_engine('mysql+pymydsql://root@localhost/mydb')

create_engine 有一个可选的 echo 参数。 如果设置为 true,引擎生成的 SQL 查询将在终端上回显。

SQLAlchemy 包含declarative_base 类。 它作为模型类和映射表的目录。

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

下一步是定义模型类。 它必须派生自 base – 如上所述的 declarative_base 类的对象。

将 __tablename__ 属性设置为您要在数据库中创建的表的名称。 其他属性与字段相对应。 每个都是 SQLAlchemy 中的 Column 对象,其数据类型来自以下列表之一 −

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

以下代码是名为 Student 的模型类映射到 Students 表。

#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) 

要创建具有相应结构的 Students 表,请执行为基类定义的 create_all() 方法。

base.metadata.create_all(engine)

我们现在必须声明一个 Student 类的对象。 所有数据库事务,如从数据库中添加、删除或检索数据等,都由 Session 对象处理。

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

存储在 Student 对象中的数据通过 session 的 add() 方法物理添加到基础表中。

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

这里是在students表中添加记录的完整代码。 在执行过程中,控制台会显示相应的SQL语句日志。

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()

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

session 对象还提供了 add_all() 方法来在单个事务中插入多个对象。

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

现在,记录已添加到表中,我们想像 SELECT 查询一样从中获取数据。 会话对象具有 query() 方法来执行任务。 查询对象由 Student 模型上的 query() 方法返回。

qry=seesionobj.query(Student)

使用此 Query 对象的 get() 方法获取与给定主键对应的对象。

S1=qry.get(1)

执行该语句时,其对应的SQL语句在控制台回显如下 −

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,)

query.all() 方法返回可以使用循环遍历的所有对象的列表。

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)

更新映射表中的记录非常容易。 您所要做的就是使用 get() 方法获取记录,为所需的属性分配一个新值,然后使用会话对象提交更改。 下面我们将 Juhi 学生的分数更改为 100。

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

删除记录同样简单,只需从会话中删除所需的对象即可。

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