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()
完整查询语法
代码语言:javascript复制User.query.filter().order_by().offset().limit().all()
>>> 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的简写形式
>>> u1 = User.query.filter_by(name='zhangsan', role_id=1).all()
>>> u1[0]
<User 1>
- filter是万能过滤器,但是即使只差一张表,字段名都要加上对象名称
>>> user = User.query.filter(User.name=='zhangsan', User.role_id==1).all()
>>> user[0].name
'zhangsan'
执行或操作
- 查询名字为zhangsan 或邮箱以 163.com 结尾,返回一个列表
>>> 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条记录开始取
>>> li=User.query.offset(2).all()
>>> li[0].name
'wangwu'
>>> li[1].name
'zhaoliu'
- (跳过1条,取两条)
>>> User.query.offset(1).limit(2).all()
[<User 2>, <User 3>]
- 根据id反向排序,不推荐
>>> User.query.order_by("-id").all()
C:UsersAdministrator.virtualenvsflask-0VgPQDMYlibsite-packagessqlalchemysqlcompiler.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反向排序,官方推荐
>>> 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