Flask-SQLAlchemy 对数据库的过滤查询

2021-02-26 15:34:53 浏览数 (1)

使用 Flask-SQLAlchemy 从数据库中查询数据,可以指定查询的条件。数据库中的数据很多,用户需要的只是某一条数据或满足某个条件的数据。

在 Flask-SQLAlchemy 中,指定查询条件是通过数据对象的 query 对象来实现的,query 对象中实现了很多常用的过滤方法,可以方便地实现过滤查询。

一、准备数据库和数据表

1. 创建一个 flask_alchemy_search.py 文件,编写连接数据库和模型类的代码并运行,创建两个数据表。

代码语言:javascript复制
from flask import Flask
from flask_sqlalchemy import SQLAlchemy


app = Flask(__name__)


app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql://admin:Mysql!123@127.0.0.1:3306/MyDB_one'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True
app.config['SQLALCHEMY_ECHO'] = True
db = SQLAlchemy(app)


class Phone(db.Model):
    __tablename__ = 'Phone_tb'
    pid = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(32))
    person = db.relationship('Person', backref='phone', lazy='dynamic')

    def __repr__(self):
        return 'Phone_name: {}'.format(self.name)


class Person(db.Model):
    __tablename__ = 'Person_tb'
    mid = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    age = db.Column(db.Integer)
    phone_id = db.Column(db.Integer, db.ForeignKey('Phone_tb.pid'))

    def __repr__(self):
        return 'Person_name: {}'.format(self.name)


db.drop_all()
db.create_all()


if __name__ == '__main__':
    app.run(debug=True)

使用创建好的 MySQL 用户 admin 连接数据库,在 MyDB_one 数据库中先删除再创建两张数据表 Phone_tb 和 Person_tb 。

2. 创建完成数据表后,将代码中的 db.drop_all() ,db.create_all() 和 app.run(debug=True) 注释掉。

二、在数据表中批量插入数据

因为相同的代码在之前已经使用过,所以在准备数据表时,先将数据表删除了,重新建新的表。数据表是空,要查询数据,数据表中首先要有数据,先批量添加数据到数据表中。

代码语言:javascript复制
if __name__ == '__main__':

    phone_one = Phone(name='IPhone')
    phone_two = Phone(name='Mi')
    phone_three = Phone(name='NOKIA')
    phone_four = Phone(name='HUAWEI')
    phone_five = Phone(name='OPPO')
    phone_six = Phone(name='VIVO')
    db.session.add_all([phone_one, phone_two, phone_three, phone_four, phone_five, phone_six])
    db.session.commit()

    per_one = Person(name='You', age=18, phone_id=1)
    per_two = Person(name='Me', age=81, phone_id=3)
    per_three = Person(name='JackMa', age=60, phone_id=2)
    per_four = Person(name='Panshiyi', age=50, phone_id=4)
    per_five = Person(name='DingLei', age=40, phone_id=1)
    db.session.add_all([per_one, per_two, per_three, per_four, per_five])
    db.session.commit()

在 flask_alchemy_search.py 中继续添加上面的代码,运行,会在数据表 Phone_tb 中添加 6 条数据,在数据表 Person_tb 中添加 5 条数据。

这些数据用于后面使用 Flask-SQLAlchemy 进行过滤查询的素材。

三、使用 Flask-SQLAlchemy 进行过滤查询

数据添加完成,注释掉添加数据的代码,(表中有唯一字段,重复添加会报错),然后开始查询数据。

1. 查询表中的所有对象

代码语言:javascript复制
    all_person = Person.query.all()
    print(all_person)

使用 query 对象的 all() 方法来查询表中的所有数据,返回的结果是所有数据组成的一个列表,显示的字段是 __repr__ 中定义的字段。

如查询 Person_tb 中的所有数据,运行结果:

代码语言:javascript复制
[Person_name: You, Person_name: Me, Person_name: JackMa, Person_name: Panshiyi, Person_name: DingLei]

2. 查询表中的第一个对象

代码语言:javascript复制
    first = Person.query.first()
    print(first)

使用 query 对象的 first() 方法来查询表中的第一条数据。

代码语言:javascript复制
Person_name: You

3. 主键查询,如果主键不存在则无返回内容

代码语言:javascript复制
    three = Person.query.get(3)
    print(three)

使用 query 对象的 get() 方法来根据主键查询数据,在 get() 中传入一个表中存在的主键值。

代码语言:javascript复制
Person_name: JackMa

4. 精确查询,获取满足条件的数据

代码语言:javascript复制
    person_p = Person.query.filter_by(name='Panshiyi').all()
    print(person_p)

使用 query 对象的 filter_by() 方法来指定条件查询精确的数据,精确查询需要指定某个字段完整的值。

在 filter_by() 中通过键值对指定查询条件,在 filter_by() 方法后需要链式跟上 all() 方法,才能返回查询对象。

代码语言:javascript复制
[Person_name: Panshiyi]

5. 模糊查询,返回满足条件的数据

代码语言:javascript复制
    person_i = Person.query.filter(Person.name.endswith('i')).all()
    print(person_i)

使用 query 对象的 filter() 方法来查询满足条件的数据,在 filter() 中通过数据对象的字段特征来指定查询条件。

代码语言:javascript复制
[Person_name: Panshiyi, Person_name: DingLei]

6. 通过 != 进行取反查询

代码语言:javascript复制
    boss = Person.query.filter(Person.name != 'Me').all()
    print(boss)

在 filter() 方法中,指定对象属性的取反条件,可以完成逻辑非的查询。

代码语言:javascript复制
[Person_name: You, Person_name: JackMa, Person_name: Panshiyi, Person_name: DingLei]

7. and_ 进行 逻辑与 查询

代码语言:javascript复制
    from sqlalchemy import and_
    oppo = Phone.query.filter(and_(Phone.name.startswith('o'), Phone.name.endswith('o'))).all()
    print(oppo)

先从 sqlalchemy 中导入 and_ ,用于 逻辑与 查询。将并列的条件写在 and_() 中,返回结果是同时满足 and_() 中的所有条件的所有数据。

上面创建了两张数据表,现在换一张表查询,如查询开头结尾都是 o 字母的手机品牌,运行结果如下:

代码语言:javascript复制
[Phone_name: OPPO]

8. not_ 进行 逻辑非 查询

代码语言:javascript复制
    from sqlalchemy import and_, not_
    vivo = Phone.query.filter(and_(not_(Phone.name.startswith('o')), Phone.name.endswith('o'))).all()
    print(vivo)

上面使用 != 指定对象属性可以实现逻辑非,也可以使用 sqlalchemy 中的 not_ 实现逻辑非查询。

先从 sqlalchemy 中导入 not_ ,将取反的条件写在 not_() 中,返回的查询结果就是取反的结果。

代码语言:javascript复制
[Phone_name: VIVO]

9. or_ 进行 逻辑或 查询

代码语言:javascript复制
    from sqlalchemy import or_
    phone_i = Phone.query.filter(or_(Phone.name.startswith('i'), Phone.name.endswith('i'))).all()
    print(phone_i)

先从 sqlalchemy 中导入 or_ ,将查询的条件写在 or_() 中,返回的查询结果是满足其中任意一条条件的所有数据。

代码语言:javascript复制
[Phone_name: IPhone, Phone_name: Mi, Phone_name: HUAWEI]

四、Flask-SQLAlchemy 关系字段和关联查询

在上面创建的两张表中,已经设置了关系字段。

Person 与 Phone 的关系是一对多的关系。

在 Person 模型类中,定义了关系字段 phone_id 。

代码语言:javascript复制
phone_id = db.Column(db.Integer, db.ForeignKey('Phone_tb.pid'))

这个关系字段关联到了 Phone 模型类中的主键 pid 。

在 Phone 模型类中,定义了关系字段 person 。

代码语言:javascript复制
person = db.relationship('Person', backref='phone', lazy='dynamic')

通过 realtionship 描述了 Phone 和 Person 的关系,这种关系有一对多,多对多等,上面的两张表是一对多的关系,Person 是 '一' ,Phone 是 '多' ,realtionship 字段定义在 '多' 的模型类中。

在 realtionship 中,第一个参数为对应 '一' 的模型类 "Person" 。

第二个参数 backref 是在模型类 Person 中申明一条新属性的方法,这个属性名是通过关系字段查询数据时使用的属性。在数据表中,不会创建这个字段(也可以说是隐藏字段),但是这个属性名不能与 Person 中已有的属性同名,否则属性冲突,在数据表中添加数据时会报错。

第三个参数 lazy 是可选的,决定了什么时候 SQLALchemy 从数据库中加载数据,是一种优化查询速度的方式,对于数据量大或查询条件比较复杂时会有用,具体可以自己扩展一下。

接下来,进行关联查询。

代码语言:javascript复制
    me = Person.query.get(2)
    me_phone = me.phone
    print(me_phone)

先从 Person 中查出一条数据,然后通过关系字段查询 Phone 中的数据,返回的是一个 Phone 对象,而不是一个字段值。

这就完成了从 Person 中的关系字段查询到 Phone 中的对象。

代码语言:javascript复制
Phone_name: NOKIA

0 人点赞