4.使用 ORM 的数据操作

2022-08-08  本文已影响0人  SingleDiego

官方文档:






本章数据库模型

本节中的操作将在以下数据库模型里进行。

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

engine = create_engine('sqlite:///memory.db', echo=True, future=True)
Base = declarative_base()

class User(Base):
    __tablename__ = 'user_account'

    id = Column(Integer, primary_key=True)
    name = Column(String(30))
    fullname = Column(String)

    addresses = relationship("Address", back_populates="user")

    def __repr__(self):
        return f"User(id={self.id!r}, name={self.name!r}, fullname={self.fullname!r})"

class Address(Base):
    __tablename__ = 'address'

    id = Column(Integer, primary_key=True)
    email_address = Column(String, nullable=False)
    user_id = Column(Integer, ForeignKey('user_account.id'))

    user = relationship("User", back_populates="addresses")

    def __repr__(self):
        return f"Address(id={self.id!r}, email_address={self.email_address!r})"






使用 ORM 插入数据

在使用 ORM 插入时,Session 对象负责构建 Insert 结构,并在事务中发送这些结构。我们首先需要通过向 Session 添加对象;然后 Session 确保这些新条目在需要时被传送到数据库,该过程被称为刷新(flush)。

用类的实例代表数据库的行

在使用 ORM 时,我们直接使用 Python 类的实例来代表要插入的数据,这个数据库类在我们定义数据表的时候就定义好了,一个实例代表数据库中的一行。

例子:

>>> squidward = User(name="squidward", fullname="Squidward Tentacles")
>>> krabs = User(name="ehkrabs", fullname="Eugene H. Krabs")

注意,在创建实例的时候我们没有包括主键(即 id 列),因为我们想利用数据库的自动递增主键功能,如果我们要查看上述对象的 id 属性值,显示为 None

>>> squidward
User(id=None, name='squidward', fullname='Squidward Tentacles')

None 值是由 SQLAlchemy 提供的,表示该属性到目前为止还没有值。在 Python 中, SQLAlchemy 映射的属性总要返回一个值,这是为了在处理还没有赋值的新对象时,不会引发 AttributeError

到目前为止,我们上面的两个对象被成为处于"瞬时的状态”(transient)——它们没有与任何数据库状态相关联,而且还没有与一个可以为它们生成 INSERT 语句的 Session 对象相关联。

添加对象到 Session

先导入 Session 类并创建 session 对象:

>>> from sqlalchemy.orm import Session
>>> session = Session(engine)

然后使用 Session.add() 方法将这些对象添加到 session 中。现在这些对象处于待定状态,还没有被插入。

>>> session.add(squidward)
>>> session.add(krabs)

当有待处理对象时,可以通过查看 Session.new 集合来看到这个状态。

>>> session.new
IdentitySet([
  User(id=None, name='squidward', fullname='Squidward Tentacles'), 
  User(id=None, name='ehkrabs', fullname='Eugene H. Krabs')]
)
刷新

Session 使用一种被称为工作单元的模式,也就是说,它可以积累一个或多个变化,但直到需要时才将它们传递给数据库。

>>> session.flush()
BEGIN (implicit)
INSERT INTO user_account (name, fullname) VALUES (?, ?)
[...] ('squidward', 'Squidward Tentacles')
INSERT INTO user_account (name, fullname) VALUES (?, ?)
[...] ('ehkrabs', 'Eugene H. Krabs')

上诉例子中我们可以观察到 Session新增的 SQL 语句,它们现在处于开放状态,即不被执行,直到我们调用 Session.commit()Session.rollback()Session.close() 方法。

虽然 Session.flush() 可以用来手动推送当前事务的未决更改,但通常是不必要的,因为 Session 有自动刷新功能,当调用 Session.commit() 时,它就会被触发。

自动生成的主键属性

一旦执行了 session.flush(),我们创建的两个Python对象就处于一种被称为持久化的状态(persistent),在这种状态下,它们与添加或加载它们的 Session 对象相关联,并且具有许多其他的方法与属性。

另一个影响是 ORM 为每个新对象提供了新的主键标识符。它通常使用 CursorResult.inserted_primary_key 访问器。现在 squidwardkrabs 对象有了主键标识符,我们可以通过访问 id 属性来查看它们。

>>> squidward.id
4
>>> krabs.id
5
身份映射

身份映射是一个内存存储,它将当前加载在内存中的所有对象通过它们的主键身份和数据库对象联系起来。我们可以通过使用 Session.get() 方法检索上述对象。

>>> some_squidward = session.get(User, 4)
>>> some_squidward
User(id=4, name='squidward', fullname='Squidward Tentacles')
提交到数据库

使用 Session.commit() 方法把添加的事务提交到数据库并走出相应的更改。

>>> session.commit()
COMMIT






使用 ORM 更改数据

使用 ORM 更改数据也是在之前定义的数据库类的某个实例上来进行更改,我们先获取到这个实例。

>>> sandy = session.execute(select(User).filter_by(name="sandy")).scalar_one()
BEGIN (implicit)
SELECT user_account.id, user_account.name, user_account.fullname
FROM user_account
WHERE user_account.name = ?
[...] ('sandy',)
>>> sandy
User(id=2, name='sandy', fullname='Sandy Cheeks')

其实这里的 sandy 实例和我们上一小节的使用 Session.get() 方法所获得的是一样的。

>>> sandy1 = session.execute(select(User).filter_by(name="sandy")).scalar_one()
>>> sandy2 = session.get(User, 2)

>>> sandy1 == sandy2
Ture

查看一下 sandy 实例:

>>> sandy
User(id=2, name='sandy', fullname='Sandy Cheeks')

当我们尝试修改这个实例的属性, session 会跟踪这些变化。

>>> sandy.fullname = "Sandy Squirrel"

sandy 实例属性被修改后,它会被放在名为 session.dirty 的集合中。

>>> sandy in session.dirty
True

这时候使用 session.commit() 把修改提交到数据库:

>>> session.commit()

我们还可以使用第二种 ORM 的方法来修改数据。

from sqlalchemy import select, update

session.execute(
    update(User).
    where(User.name == "sandy").
    values(fullname="Sandy Squirrel Extraordinaire")
)

session.commit()






使用 ORM 删除数据

我们通过使用 Session.delete() 方法来标记删除的数据。

>>> patrick = session.get(User, 3)
SELECT user_account.id AS user_account_id, user_account.name AS user_account_name,
user_account.fullname AS user_account_fullname
FROM user_account
WHERE user_account.id = ?
[...] (3,)
>>> session.delete(patrick)
上一篇下一篇

猜你喜欢

热点阅读