前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[742]Flask数据库过滤器与查询集

[742]Flask数据库过滤器与查询集

作者头像
周小董
发布2020-01-13 17:43:42
6.8K0
发布2020-01-13 17:43:42
举报
文章被收录于专栏:python前行者python前行者
代码语言:javascript
复制
pip install flask-sqlalchemy
pip install flask-mysqldb
pip install pymysql

flask-sqlalchemy所作的操作只是把模型类转换为sql语句,然后通过数据库驱动访问mysql,在获取到结果后再把数据转换为模型对象

Flask的数据库设置:

代码语言:javascript
复制
app.config[‘SQLALCHEMY_DATABASE_URI’] = 'mysql://root:root@127.0.0.1:3306/test'

设置每次请求结束后会自动提交数据中的更改,官方不推荐设置
app.config[‘SQLALCHEMY_COMMIT_ON_TEARDOWN’] = True

如果一旦在数据库中把表结构修改,那么在sqlalchemy中的模型类也进行修改
app.config[‘SQLALCHEMY_TRACK_MODIFICATIONS’] = True

查询时显示原始SQL语句
app.config[‘SQLALCHEMY_ECHO’] = True

db = SQLAlchemy(app)

创建daemo_db.py内容如下

代码语言:javascript
复制
# coding:utf-8
from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)


class Config(object):
    SQLALCHEMY_DATABASE_URI = "mysql://root:root@127.0.0.1:3306/db_python04"
    # 设置sqlalchemy自动跟踪数据库
    SQLALCHEMY_TRACK_MODIFICATIONS = True


app.config.from_object(Config)

# 表名的常见规范,并不是以数据库模型名称命名
# ihome -> ih_user    数据库名缩写_表名
# tbl_user            tbl_表名
# 创建数据库sqlalchemy工具对象
db = SQLAlchemy(app)


# 创建数据库模型类
class Role(db.Model):
    __tablename__ = "tbl_roles"
    # 数据库中真实存在的字段, db.Column
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    # 数据库中不真实存在的,比如模型与模型之间的一种关联,根据角色查询属于这个角色的用户有哪些
    # 这里的设计不像外键是根据表的实际情况考虑,而根据模型考虑的
    # User 是让role对象可以获得user中的属性
    # backref="role"可以让user对象有个role属性获得role中的信息,这个不是必须添加的,如果不添加那么user对象要通过外键role_id获得这个用户的角色信息
    users = db.relationship("User", backref="role")


class User(db.Model):
    __tablename__ = "tbl_users"
    id = db.Column(db.Integer, primary_key=True)  # 整型的主键,会默认设置为自增主键
    name = db.Column(db.String(64), unique=True)
    email = db.Column(db.String(126), unique=True)
    password = db.Column(db.String(128))
    role_id = db.Column(db.Integer, db.ForeignKey("tbl_roles.id"))  # 外键


# @app.route('/')
# def index():

if __name__ == '__main__':
    # app.run()
    # 清除数据库的所有数据
    db.drop_all()
    # 创建表
    db.create_all()
    # 添加数据
    # 创建对象
    role1 = Role(name="admin")
    # 用session记录对象任务
    db.session.add(role1)
    # 提交任务到数据库中
    db.session.commit()

    role2 = Role(name="stuff")
    db.session.add(role2)
    db.session.commit()

    us1 = User(name='zhangsan', email='zhangsan@163.com', password='123', role_id=role1.id)
    us2 = User(name='lisi', email='lisi@163.com', password='123', role_id=role2.id)
    us3 = User(name='wangwu', email='wangwu@163.com', password='123', role_id=role2.id)
    us4 = User(name='zhaoliu', email='zhaoliu@163.com', password='123', role_id=role1.id)

    # 一次保存多条数据
    db.session.add_all([us1, us2, us3, us4])
    db.session.commit()
代码语言:javascript
复制
# 使用db.session查询指定对象的所有记录
# 这是sqlalchemy提供的最底层的方法,是flask-sqlalchemy查询
db.session.query(Role).all()
db.session.query(Role).first()

# 查询Role对象的所有数据,结果是一个列表
# 这是flask-sqlalchemy封装sqlalchemy后的方法
li = Role.query.all()

# 获得一个role类型的对象
r = li[0]

# 获得对象的一个属性值
r.name
代码语言:javascript
复制
>>> li = Role.query.all()
>>> r = li[0]
>>> r
<Role 1>
>>> r.name
'admin'
>>>

# 查询第一条记录
>>> r = Role.query.first()
>>> r.name
'admin'
>>>

# 获取一个具体对象,必须接受一个参数,必须是主键的值
>>> r = Role.query.get(2)
>>> r.name
'stuff'

常用的sqlalchemy查询过滤器

过滤器 说明

filter() 把过滤器加到原查询上,返回一个新查询 filter_by() 把等值过滤加到原查询上,返回一个新查询 limit 使用知道的值限定原查询返回的结果 offset() 偏移原查询返回的结果,返回一个新查询 order_by() 根据指定条件对原查询结果进行排序,返回一个新查询 group_by() 根据指定条件对原查询结果进行分组,返回一个新查询

只针对user表进行查询,那么user的字段就可以进行简写操作 返回一个查询,如果要获得结果还需要在结尾加 all() 或first()

完整查询语法

User.query.filter().order_by().offset().limit().all()

代码语言:javascript
复制
>>> u1 = User.query.filter_by(name='zhangsan').all()
>>> u1
[<User 1>]
>>> u1[0].name
'zhangsan'
>>> u1[0].email
'zhangsan@163.com'
>>> u2 = User.query.filter_by(name='zhangsan').first()
>>> u2.name
'zhangsan'
>>> u2.id
1
>>> u2.email
'zhangsan@163.com'
  • 查询条件两个,以 and 的方式拼接,并且匹配方式必须是完全匹配 =,不能使用模糊查询,filter_by是filter的简写形式
代码语言:javascript
复制
>>> u1 = User.query.filter_by(name='zhangsan', role_id=1).all()
>>> u1[0]
<User 1>
  • filter是万能过滤器,但是即使只差一张表,字段名都要加上对象名称
代码语言:javascript
复制
>>> user = User.query.filter(User.name=='zhangsan', User.role_id==1).all()
>>> user[0].name
'zhangsan'
执行或操作
  • 查询名字为zhangsan 或邮箱以 163.com 结尾,返回一个列表
代码语言:javascript
复制
>>> from sqlalchemy import or_
>>> li = User.query.filter(or_(User.name=='zhangsan',User.email.endswith("163.com"))).all()
>>> li[0].name
'zhangsan'
>>> li[1].name
'lisi'
  • (跳过两条记录)从第3条记录开始取
代码语言:javascript
复制
>>> li=User.query.offset(2).all()
>>> li[0].name
'wangwu'
>>> li[1].name
'zhaoliu'
  • (跳过1条,取两条)
代码语言:javascript
复制
>>> User.query.offset(1).limit(2).all()
[<User 2>, <User 3>]
  • 根据id反向排序,不推荐
代码语言:javascript
复制
>>> User.query.order_by("-id").all()
C:\Users\Administrator\.virtualenvs\flask-0VgPQDMY\lib\site-packages\sqlalchemy\sql\compiler.py:763: SAWarning: Can't resolve label reference '-id'; converting to text() (this warning may be suppressed after 10 oc
currences)
  util.ellipses_string(element.element),
[<User 4>, <User 3>, <User 2>, <User 1>]
  • 根据id反向排序,官方推荐
代码语言:javascript
复制
>>> User.query.order_by(User.id.desc()).all()
[<User 4>, <User 3>, <User 2>, <User 1>]

group_by语句不能用flask-sqlalchemy的对象进行操作,必须用sqlalchemy最原始的方式进行操作,并要冲sqlalchemy中导入func这个工具

进行分组查询,query中必须包含分组后必须显示出的字段

代码语言:javascript
复制
>>> from sqlalchemy import func
>>> db.session.query(User.role_id,func.count(User.role_id)).group_by(User.role_id).all()
[(1, 2), (2, 2)]

对应 的sql语句

代码语言:javascript
复制
select role_id,count(role_id) from tbl_users group by role_id;
更新操作
代码语言:javascript
复制
# 先获取对象
# 修改对象属性
# 将对象修改后更新到数据库
>>> user = User.query.get(1)
>>> user.name = "python"
>>> db.session.add(user)
>>> db.session.commit()
>>> User.query.get(1)
>>> u1=User.query.get(1)
>>> u1.name
'python'

# 查询出结果过直接更新
>>> User.query.filter_by(name="wangwu").update({"name":"linux","email":"linux@163.com"})
1
>>> db.session.commit()
删除操作
代码语言:javascript
复制
>>> user = User.query.get(3)
>>> db.session.delete(user)
>>> db.session.commit()
>>> User.query.all()
[<User 1>, <User 2>, <User 4>]

1 查询集 : 指数据查询的集合

原始查询集: 不经过任何过滤返回的结果为原始查询集 数据查询集: 将原始查询集经过条件的筛选最终返回的结果

查询过滤器:

过滤器

功能

cls.query.filter(类名.属性名 条件操作符 条件)

过滤特定条件,返回的是query对象

cls.query.filter_by(关键字参数对)

单条件查询,条件必须关键字参数,而且and连接

cls.query.offset(num)/查询集对象.offset(num)

针对filter查询集对象偏移

cls.query.limit(num)

针对查询集取两条数据

cls.query.order_by(属性名).limit(num); cls.query.order_by( -属性名).limit(num)

按属性名排序,取limit(num) 升序排列;按属性名排序,取limit(num) 降序排列

cls.query.groupby()

原查询分组,返回新查询

查询执行函数

查询执行方法

说明

cls.query.all()

所有的数据查询集,返回对象列表,不能链式调用

cls.query.first()

取第一个

cls.query.get(值) User.query.get(10)

取得id的值对应的数据

cls.query.filter().count()

返回查询结果数量

cls.query.filter().paginate()

返回paginate对象,此对象用于分页

cls.query.filter(类名.属性名.like(‘%值%’))

like模糊查询

cls.query.filter(类名.属性名.contains(‘值’))

contains包含某个值

cls.query.filter(User.username.startswith(‘张’))

startswith 以…开头/endswith以…结尾

cls.query.filter(User.id.in_([list]))

in_ 和 not in 是否包含某个范围内

cls.query.filter(User.id.is_(None))

is_ isnot 查询为null/不为null 的数据

2 查询过滤器实例

(1) all() 得到所有的数据查询集 返回列表

类名.query.all() 不能够链式调用

代码语言:javascript
复制
@view.route('/all/')
def all():
    data = User.query.all()
    print(data)
    return '删除数据'
(2) filter() 过滤默认查询所有

类名.query.filter() 类名.query.filter(类名.属性名 条件操作符 条件)

代码语言:javascript
复制
#filter 获取所有数据查询集
@view.route('/filter/')
def filter():
    # data = User.query.filter()
    # data = User.query.filter(User.username=='王五')
    data = User.query.filter(User.username=='王五',User.sex==False)
    print(data)
    for i in data:
        print(i.username,i.sex)
    return '删除数据'
(3) filter_by() 单条件查询
代码语言:javascript
复制
@view.route('/filter_by/')
def filter_by():
    # data = User.query.filter_by()
    data = User.query.filter_by(age=18)
    #只能为下面这种关键字的用法   且多个添加为and操作
    # data = User.query.filter_by(username='王五',sex=False)
(4) offset(num) 偏移量
代码语言:javascript
复制
@view.route('/offset/')
def offset():
    # data = User.query.filter().offset(1)
    # data = User.query.filter().offset(2)
    #错误的用法
    data = User.query.all().offset(2)
    # print(User.query.filter())
    # print(data)
    # for i in data:
    #     print(i.username,i.sex)
    return '删除数据'
(5) limit() 取值
代码语言:javascript
复制
@view.route('/offsetlimit/')
def offsetlimit():
    data = User.query.offset(2).limit(2)
    print(data)
    for i in data:
        print(i.username,i.sex)
    return 'limit'
(6) order_by() 排序

默认升序 -属性名

代码语言:javascript
复制
@view.route('/orderby/')
def orderby():
    #升序
    data = User.query.order_by(User.age).limit(1)
    #降序
    data = User.query.order_by(-User.age).limit(1)

3 查询执行函数

(1) first() 取出一条数据
代码语言:javascript
复制
@view.route('/first/')
def first():
    # data = User.query.first() == User.query.get(1)
    # data = User.query.order_by(-User.age).first()
    data = User.query.order_by(User.age).first()
    print(data.age)
    print(data.username)
    # for i in data:
    #     print(i.username,i.sex)
(2) get() 取得id值的数据

查询成功 返回 对象 查询失败 返回 None

代码语言:javascript
复制
data = User.query.get(10)  #找到id=10的数据
print(data)
(3) contains 包含关系

类名.query.filter(类名.属性名.contains(‘值’))

代码语言:javascript
复制
data = User.query.filter(User.username.contains('五'))
(4) like 模糊查询

类名.query.filter(类名.属性名.like(‘%值%’))

代码语言:javascript
复制
data = User.query.filter(User.username.like('%张%')) #包含张
data = User.query.filter(User.username.like('%张'))  #以张作为结尾 
data = User.query.filter(User.username.like('张%'))  #以张作为开头
(5) startswith 以…开头 endswith以…结尾
代码语言:javascript
复制
data = User.query.filter(User.username.startswith('张')) #以 张作为开头
data = User.query.filter(User.username.endswith('张'))   #以张作为结尾
(6) 比较运算符
代码语言:javascript
复制
1. __gt__ 大于
2. __ge__ 大于等于
3. __lt__ 小于
4. __le__ 小于等于
5. >   <
6. >=  <=
7. !=   ==
代码语言:javascript
复制
data = User.query.filter(User.id>1) #查询id大于1的数据
data = User.query.filter(User.id.__gt__(1)) #查询id大于1的数据
data = User.query.filter(User.id.__ge__(1)) #查询id大于1的数据
data = User.query.filter(User.id>=1) #查询id大于1的数据
data = User.query.filter(User.id<3) #查询id大于1的数据
data = User.query.filter(User.id.__lt__(3)) #查询id大于1的数据
(7) in_ 和 not in 是否包含某个范围内
代码语言:javascript
复制
#in的使用
@view.route('/in/')
def myin():
    data = User.query.filter(User.id.in_([1,2,3,4])) #在...范围内
    data = User.query.filter(~User.id.in_([1,2,3,4])) #not in不再...范围内
    data = User.query.filter(User.username.in_(['张三','王五']))
    return render_template('show.html',data=data)
(8) is_ / isnot 查询为null/不为null 的数据
代码语言:javascript
复制
#对于null数据的处理
@view.route('/null/')
def null():
    #查询为null数据的
    data = User.query.filter(User.username.is_(None))
    data = User.query.filter(User.username == None)
    data = User.query.filter(~User.username.isnot(None))
    #查询不为null数据的
    data = User.query.filter(~User.username.is_(None))
    data = User.query.filter(User.username.isnot(None))
    data = User.query.filter(User.username != None)

    return render_template('show.html',data=data)
(9) count 统计
代码语言:javascript
复制
@view.route('/count/')
def mycount():
    #统计性别为sex的数据条数
    data = User.query.filter(not_(User.sex == True)).count()
    #统计所有数据的条数
    data = User.query.filter().count()
    data = User.query.count()
    return '{}条数据'.format(data)

4 数据库逻辑查询

代码语言:javascript
复制
from sqlalchemy import and_,or_,not_
(1) 逻辑与 and_
代码语言:javascript
复制
#逻辑操作
@view.route('/and/')
def myand():
    data = User.query.filter(User.sex==True,User.age<20)
    data = User.query.filter(User.sex==True).filter(User.age<20)
    data = User.query.filter(and_(User.sex==True,User.age<20))
    return render_template('show.html',data=data)
(2) 逻辑或 or_
代码语言:javascript
复制
#逻辑操作
@view.route('/or/')
def myor():
    #or
    data = User.query.filter(or_(User.sex==True,User.age<20),User.id.in_([1,2,3]))
    #and 和 or的 一起使用
    data = User.query.filter(or_(User.sex==True,User.age<20))
    return render_template('show.html',data=data)
(3) 逻辑非 not_
代码语言:javascript
复制
#逻辑操作
@view.route('/not/')
def mynot():
    data = User.query.filter(not_(User.sex==True))
    #错误写法只能有一个条件
    data = User.query.filter(not_(User.sex==True,User.id!=1))
    data = User.query.filter(~User.sex==True)
    return render_template('show.html',data=data)

5 flask-migrate 文件的迁移

安装:

代码语言:javascript
复制
flask-script
flask-migrate

使用

代码语言:javascript
复制
from flask_migrate import Migrate,MigrateCommand

migrate = Migrate(app,db)   #将app与db进行关联
manager = Manager(app)
manager.add_command('db',MigrateCommand) #给manage添加迁移文件的命令db
(1) 生成迁移文件目录
代码语言:javascript
复制
python3 manage.py db init

生成 一个 migrations的迁移文件目录

(2) 生成迁移文件
代码语言:javascript
复制
python3 manage.py db migrate
(3) 执行迁移文件
代码语言:javascript
复制
python3 manage.py db upgrade

创建数据库模型

创建数据库模型的方法如下,创建表时必须导入基类:

代码语言:javascript
复制
class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), unique=True, index=True)
    def __repr__(self):
        return '<User %r>' % self.username

这个模型创建了两个字段,他们是类db.Column的实例,id和username,db.Column 类构造函数的第一个参数是数据库列和模型属性的类型,下面列出了一些常见的列类型以及在模型中使用的Python类型。

Integer:普通整数,一般是32bit String:变长字符串 Text:变长字符串,对较长或不限长度的字符做了优化 Boolean:布尔值 Date:日期 DateTime:日期和时间

db.Column 中其余的参数指定属性的配置选项。下面列出了一些常用选项:

primary_key:如果设置为True,这列就是表的主键 unique:如果设置为True,这列不允许出现重复的值 index:如果设置为True,为这列创建索引,提升查询效率 default:为这列定义默认值

一对多关系

最为常见的关系就是一对多关系,因为关系在它们建立之前就已经声明。关系使用relationship()函数表示,外键使用类sqlalchemy.schema.ForeignKey来单独声明。

在一对多关系中,要在这一侧加入一个外键,指向这一侧联接的记录,即relationship()声明出现在代表那个类,而外键声明出现在代表的那个类中。如下代码所示,每一个人(少)可以有多个地址(多):

代码语言:javascript
复制
class Person(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    address = db.relationship('Address', backref='person', lazy='dynamic')

class Address(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    person_id = db.Column(db.Integer, db.ForeignKey('person.id'))

关系使用address表中的外键连接了两行。添加到address模型中person_id列被定义为外键,就是这个外键建立起了联系。传给db.ForeignKey()的参数’person_id’表明,这一列的值是person表中行的id值。

添加到person表中的address属性代表这个关系的面向对象视角。对于一个person实例,其address属性将返回与person相关联的多个地址。db.relationship()的第一个参数表明这个关系的另一端是哪个模型。

db.relationship()中的backref参数向address模型中添加一个person属性,从而定义反向关系。这一属性可替代person_id访问 person模型,此时获取的是模型对象,而不是外键的值。

大多数情况下,db.relationship()都能自行找到关系中的外键,但有时却无法决定把哪一列作为外键。例如如果address模型中有两个或以上的列定义为person模型的外键,SQLAlchemy就不知道该使用哪列。如果无法决定外键,你就要为db.relationship()提供额外参数,从而确定所用外键,常用的配置选项如下所示:

  • backref:在关系的另一个模型中添加反向引用
  • primary join:明确指定两个模型之间使用的联结条件。只在模棱两可的关系中需要指定
  • lazy:决定了SQLAlchemy什么时候从数据库中加载数据。可选值有 select(首次访问时按需加载)、immediate(源对象加载后就加载)、 joined(加载记录,但使用联结)、 subquery (立即加载,但使用子查询),noload(永不加载)和 dynamic(不加载记录,但提供加载记录的查询)
  • uselist:如果设为Fales,表示一对一关系
  • order_by:指定关系中记录的排序方式
  • secondary:指定多对多关系中关系表的名字
  • secondaryjoin:SQLAlchemy无法自行决定时,指定多对多关系中的二级联结条件

如果想为反向引用(backref)定义惰性(lazy)状态,可以使用**backref()**函数:

代码语言:javascript
复制
class Person(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    address = db.relationship('Address',
        backref=db.badkref('person', lazy='joined'),
        lazy='dynamic')
多对多关系

一对多关系,一对一关系至少有一侧是单个实体,所以记录之间的联系可以通过外键来实现,让外键指向这个实体。但是两侧都是多的关系,显然不能通过一个简单的外键来实现。解决办法是添加第三张表。

多对多关系一个典型的例子是文章与标签之间的关系,一篇文章可以有多个标签,一个标签也可以对应多篇文章。 我们把tags和posts表之间的多对多关系转换成它们各自与关联表connections之间的两个一对多关系。

查询这个多对多关系分为两步。若想知道某篇文章有多少个标签,首先从posts和connections之间的一对多关系开始,获取这篇文章在connections表中的所有和这篇文章相关的记录,然后再按照多到一的关系在tags表中查找对应的所有标签。

同样,若想查找某个标签所对应的所有文章,首先从tags表和connections表之间的一对多关系开始,获取这个标签在connections表中所有的和这个标签相关的记录,然后再按照多到一的关系在posts表中查找对应的所有文章。

代码语言:javascript
复制
connections = db.Table('connections',
db.Column('posts_id', db.Integer, db.ForeignKey('posts_id')),
db.Column('tags_id', db.Integer, db.ForeignKey('tags_id')))

class Post(db.Model):
    __tablename__ = 'posts'
    id = db.Column(db.Integer, primary_key=True)
    tags = db.relationship('Tag', secondary=connections,
    backref=db.backref('posts', lazy='dynamic'),lazy='dynamic')

class Tag(db.Model):
    __tablename__ = 'tags'
    id = db.Column(db.Integer, primary_key=True)

多对多关系仍使用定义一对多关系的db.relationship()方法进行定义,但在多对多关系中,必须把secondary参数设为关联表。多对多关系可以在任何一个类中定义,backref参数会处理好关系的另一侧。关联表connections就是一个简单的表,不是模型,SQLAlchemy会自动接管这个表。

自引用关系

多对多关系在我们的Web应用中可以用来实现用户之间的关注,但是在上面的文章和标签的例子中,关联表连接的是两个明确的实体,而在用户关注其他用户时,都在users表内,只有一个实体。如果关系中的两侧都在同一个表中,这种关系称为自引用关系。在关注中,关系的左侧是用户实体,称为”关注者”;右侧也是用户实体,称为”被关注者”。 这种用户之间关注的关系,我们依然可以使用上面的方法来实现。

高级多对多关系

自引用多对多关系可在数据库中表示用户之间的关注,但却有个限制。使用多对多关系时,往往需要存储所联两个实体之间的额外信息。对用户之间的关注来说,可以存储用户关注另一个用户的日期,这样就能按照时间顺序列出所有关注者。这种信息只能存储在关联表中,但是在之前实现的学生和课程之间的关系中,关联表完全是由SQLAlchemy掌控的内部表。 为了能在关系中处理自定义的数据,我们必须提升关联表的地位,使其变成程序可访问的模型。

代码语言:javascript
复制
class Follow(db.Model):
    __tablename__ = 'follows'
    follower_id = db.Column(db.Integer, db.ForeignKey('users.id'), primary_key=True)
    followed_id = db.Column(db.Integer, db.Foreignkey('users.id'), primary_key=True)
    timestamp = db.Column(db.DateTime, default=datetime.utcnow)

SQLAlchemy不能直接使用这个关联表,因为如果这么做程序就无法访问其中的自定义字段。相反地,要把这个多对多关系的左右两侧拆分成两个基本的一对多关系,而且要定义成标准的关系。

代码语言:javascript
复制
class User(db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    followed = db.relationship('Follow', foreign_keys=[Follow.follower_id],
        backref=db.backref('follower', lazy='joined'),
        lazy='dynamic', cascade='all, delete-orphan')
    follower = db.relationship('Follow', foreign_keys=[Follow.followed_id],
        backref=db.backref('followed', lazy='joined'),
    lazy='dynamic', cascade='all, delete-orphan')

followd和follower都定义为单独的一对多关系,为了消除外键之间的歧义,定义关系时必须选用可选参数foreign_keys指定外键。而且,db.backref()不指定这两个关系之间的引用关系,而是回引Follow模型。

回引中的 lazy 参数指定为 joined 。这个 lazy 模式可以实现立即从联结查询中加载相关对象。例如,如果某个用户关注了 100 个用户,调用user.followed.all()后会返回一个列表,其中包含100个Follow实例,每一个实例的follower和followed回引属性都指向相应的用户。设定为lazy=’joined’模式,就可在一次数据库查询中完成这些操作。如果把lazy设为默认值select,那么首次访问follower和followed属性时才会加载对应的用户,而且每个属性都需要一个单独的查询,这就意味着获取全部被关注用户时需要增加100次额外的数据库查询。

这两个关系中,User一侧设定的lazy参数作用不一样。lazy参数都在“一”这一侧设定,返回的结果是“多”这一侧中的记录。上述代码使用的是dynamic,因此关系属性不会直接返回记录,而是返回查询对象,所以在执行查询之前还可以添加额外的过滤器。

cascade 参数配置在父对象上执行的操作对相关对象的影响。比如,层叠选项可设定为:将用户添加到数据库会话后,要自动把所有关系的对象都添加到会话中。层叠选项的默认值能满足大多数情况的需求,但对这个多对多关系来说却不合用。删除对象时,默认的层叠行为是把对象联接的所有相关对象的外键设为空值。但在关联表中,删除记录后正确的行为应该是把指向该记录的实体也删除,因为这样能有效销毁联接。这就是层叠选项值delete-orphan的作用。

操作数据库
代码语言:javascript
复制
#创建表
db.create_all()
#删除表
db.drop_all()
#插入行
user_john=User(username='john')
#添加到数据库会话
db.session.add(user_john)
#提交
db.session.commit()
#删除行
db.session.delete(user_john)
db.session.commit()
#查询行
User.query.all()

使用过滤器可以配置query对象进行更精确的数据库查询。下面列出常用的过滤器,完整的列表请参见SQLAlchemy官方文档:

filter():把过滤器添加到原查询上,返回一个新查询 filter_by():把等值过滤器添加到原查询上,返回一个新查询 limit():使用指定的值限制原查询返回的结果数量,返回一个新查询 offset():偏移原查询返回的结果,返回一个新查询 order_by():根据指定条件对原查询结果进行排序,返回一个新查询 group_by():根据指定条件对原查询结果进行分组,返回一个新查询

在查询上应用指定的过滤器后,通过调用all()执行查询,以列表的形式返回结果。除了all()之外,还有其他方法能触发查询执行。下面列出常用的执行查询方法:

all():以列表形式返回查询的所有结果 first():返回查询的第一个结果,如果没有结果,则返回 None first_or_404():返回查询的第一个结果,如果没有结果,则终止请求,返回 404 错误响应 get():返回指定主键对应的行,如果没有对应的行,则返回 None get_or_404():返回指定主键对应的行,如果没找到指定的主键,则终止请求,返回 404 错误响应 count():返回查询结果的数量 paginate():返回一个 Paginate 对象,它包含指定范围内的结果

来源:https://www.codercto.com/a/58026.html https://blog.csdn.net/weixin_41829272/article/details/80609968 https://blog.csdn.net/LYLLOAD/article/details/81482087

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-12-22 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 常用的sqlalchemy查询过滤器
    • 执行或操作
      • 更新操作
        • 删除操作
          • (1) all() 得到所有的数据查询集 返回列表
          • (2) filter() 过滤默认查询所有
          • (3) filter_by() 单条件查询
          • (4) offset(num) 偏移量
          • (5) limit() 取值
          • (6) order_by() 排序
          • (1) first() 取出一条数据
          • (2) get() 取得id值的数据
          • (3) contains 包含关系
          • (4) like 模糊查询
          • (5) startswith 以…开头 endswith以…结尾
          • (6) 比较运算符
          • (7) in_ 和 not in 是否包含某个范围内
          • (8) is_ / isnot 查询为null/不为null 的数据
          • (9) count 统计
          • (1) 逻辑与 and_
          • (2) 逻辑或 or_
          • (3) 逻辑非 not_
          • (1) 生成迁移文件目录
          • (2) 生成迁移文件
          • (3) 执行迁移文件
      • 1 查询集 : 指数据查询的集合
      • 2 查询过滤器实例
      • 3 查询执行函数
      • 4 数据库逻辑查询
      • 5 flask-migrate 文件的迁移
      • 创建数据库模型
        • 一对多关系
          • 多对多关系
          • 自引用关系
          • 高级多对多关系
            • 操作数据库
            相关产品与服务
            数据库
            云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档