数据库操作

现在我们创建了模型,生成了数据库和表,下面来学习常用的数据库操作,数据库操作主要是CRUD,即Create(创建)、Read(读取/查询)、Update(更新)和Delete(删除)。

SQLAlchemy使用数据库会话来管理数据库操作,这里是数据库会话也称为事务(transaction)。falsk-sqlalchemy自动帮我们创建会话,可以通过db.session属性获取。

 

数据库中的会话代表一个临时存储区,对数据库做出的改动都会存放到这里。你可以调用add()方法将新创建的对象添加到数据库会话中,或是对会话中的对象进行更新。只有当你对数据库会话对象调用commit()方法时,改动才会提交到数据库,这确保了数据提交的一致性。另外,数据库会话也支持回滚操作。当你对会话调用rollback()方法时,添加到会话中且未提交的改动都将被撤销。

CRUD

下面我们在python shell中进行CRUD操作。默认情况下,flask-sqlalchemy(>=2.3.0版本)会自动为模型类生成一个__repr__()方法。当在python shell中调用模型类的对象时,__repr__()方法会返回一条来说“<模型类名主键值>”的字符串,如<Note 2>。下面的示例中,模型类都重新定义了__repr__()方法,返回以下更有用的信息,比如:

class Note(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    body = db.Column(db.Text)

    def __repr__(self):
        # %r是用repr()方法处理对象,返回类型本身,而不进行类型转换
        return "<Note %r>" % self.body

在实际开发中,这并不是必须的。

Create

添加一条新记录到数据库分三步:

  1. 创建python对象(实例化模型类)作为一条记录;
  2. 添加新创建的记录到数据库会话;
  3. 提交数据库会话

下面的示例向数据库中添加了三条留言:

>>> from app import db,Note

>>> note1 = Note(body='remember sam')

>>> note2 = Note(body='Rose')

>>> note3 = Note(body='I LIKE FLASK')

>>> db.session.add(note1)

>>> db.session.add(note2)

>>> db.session.add(note3)

>>> db.session.commit()

在这个例子中,首先从app模块中导入db对象和Note类,然后分别创建3个Note实例表示3条记录,使用关键字参数传入字段数据。我们的Note类继承自db.Model基类,db.Model基类会为Note类提供一个构造函数,接收匹配类属性名称的参数值,并赋值给对应的类属性,所以我们不需要自己在Note类中定义构造方法。接着我们调用add()方法把这三个Note对象添加到会话对象db.session中,最后调用commit()方法提交会话。

 

除了依次调用add()方法添加多个记录,也可以使用add_all()依次添加包含所有记录对象的列表。我们在创建模型类实例的时候并没有定义id字段的数据,这是因为主键由SQLAlchemy管理。模型类对象创建后作为临时对象(transient),当你提交数据库会话后,模型类对象才会转换为数据库记录写入数据库中,这时模型类对象会自动获取id值:

>>> note2.id

2

flask-sqlalchemy提供了一个SQLALCHEMY_COMMIT_ON_TEARDOWN配置,将其设为True可以设置自动调用commit()方法提交数据库会话。因为存在潜在的bug,目前不建议使用。可以使用db.session.commit()方法的方式提交数据库会话。

read

如何从数据库取回数据呢,使用模型类提供的query属性附加调用各种过滤方法及查询方法即可完成此任务。一般来说,一个完整的查询遵循下面的模式:

<模型类>.query.<过滤方法>.<查询方法>

从某个模型类触发,通过在query属性对应的Query对象上附加的过滤方法和查询函数对模型类对应的表中的记录进行各种筛选和调整,最终返回包含对应数据库记录数据的模型类实例,对返回的实例调用属性即可获取对应的字段数据。

SQLAlchemy提供了许多查询方法用来获取记录,如:

fastapi sqlalchemy orm query 用法 sqlalchemy crud_数据库

fastapi sqlalchemy orm query 用法 sqlalchemy crud_sqlalchemy_02

 

表中的first_or_404()、get_or_404()以及paginate()方法时flask-sqlalchemy附加的查询方法。

SQLAlchemy还提供了许多过滤方法,使用这些过滤方法可以获取更精确的查询,比如获取指定字段值的记录。对模型类的query属性存储的query对象调用过滤方法将返回一个更精确的query对象(简称为查询对象)。因为每个过滤方法都会返回新的查询对象,所以过滤器可以叠加使用。在查询对象上调用前面说的查询方法,即可获得一个包含过滤后的记录的列表。常用的查询过滤方法如下:

fastapi sqlalchemy orm query 用法 sqlalchemy crud_字段_03

 

下面是对Note类进行查询和过滤的几个例子。

all()返回所有记录:

>>> from app import db,Note
>>> Note.query.all()
[<Note 'remember sam'>, <Note 'Rose'>, <Note 'I LIKE FLASK'>]
>>>

first()返回第一条记录:

>>> from app import db,Note
>>> note = Note.query.first()
>>> note
<Note 'remember sam'>

get()返回指定主键值(id字段)的记录:

>>> note = Note.query.get(2)
>>> note
<Note 'Rose'>
>>> note.body
'Rose'

count()返回记录的数量:

>>> Note.query.count()
3

filter()方法:

filter()是最基础的查询方法,它使用指定的规则来过滤记录,下面的示例在数据库中找出了body字段值为Rose的记录:

>>> Note.query.filter(Note.body=='Rose').first()
<Note 'Rose'>
>>>

 

直接打印查询对象或将其转换为字符串可以查看对应当前的SQL语句:

>>> print(Note.query.filter(Note.body=='Rose'))
SELECT note.id AS note_id, note.body AS note_body
FROM note
WHERE note.body = ?

在filter()方法中传入表达式时,除了==以及表示不等的!=,其它常用的查询操作符即使用示例如下

like:

>>> Note.query.filter(Note.body.like('%Sam%')).first()
<Note 'remember sam'>

in:

>>> Note.query.filter(Note.body.in_(['Rose','Sam'])).first()
<Note 'Rose'>

not in:

>>> Note.query.filter(~Note.body.in_(['Rose'])).all()
[<Note 'remember sam'>, <Note 'I LIKE FLASK'>]

and:

>>> from sqlalchemy import and_
>>> Note.query.filter(and_(Note.body=='Rose', Note.id==2)).all()
[<Note 'Rose'>]

 

或者在filter()中加入多个表达式,使用逗号分隔

>>> Note.query.filter(Note.body=='Rose', Note.id==2).all()
[<Note 'Rose'>]

 

或者叠加调用多个filter()/filter_by()方法

>>> Note.query.filter(Note.body=='Rose').filter(Note.id==2).all()
[<Note 'Rose'>]
>>> Note.query.filter_by(body='Rose').filter_by(id=2).all()
[<Note 'Rose'>]

注意:filter()中是2个等号,filter_by()是1个等号,和filter()相比,filter_by()方法更易于使用。在filter_by()方法中,可以使用关键字表达式来指定过滤规则。更方便的是可以在过滤器中直接使用字段名称。

or:

>>> from sqlalchemy import or_
>>> Note.query.filter(or_(Note.body=='Rose',Note.id==3)).all()
[<Note 'Rose'>, <Note 'I LIKE FLASK'>]
>>>

update

更新一条记录很简单,直接赋值给模型类的字段属性就可以改变字段值,然后调用commit()方法提交会话即可,例如:

>>> note = Note.query.get(2)
>>> note.body
'Rose'
>>> note.body = 'Life is a dream'
>>> db.session.commit()
>>> note.body
'Life is a dream'

只有要插入新的记录或要将现有的记录添加到会话中时才需要使用add()方法,单纯要更新

现有的记录时只需要直接为属性赋值然后提交到会话即可。

delete

删除记录和添加记录类似,不过要把add()方法改为delete()方法,最后都要调用commit()方法提交记录。例如删除id为2的记录:

>>> note = Note.query.get(1)
>>> db.session.delete(note)
>>> db.session.commit()
>>> Note.query.count()
2
>>>