好风凭借力,送我上青云。
1. 排序
1.1 order_by
- 正序
session.query(Article).order_by("-create_time").all()
- 逆序:个人测试无法直接使用
-create_time
方式,需要导入text
from sqlalchemy import text
session.query(Article).order_by(text("-create_time")).all()
1.2 __mapper_args__
class Article(Base):
......
__mapper_args__ = {
"order_by": create_time,
# 倒叙方式一
"order_by": create_time.desc()
# 倒叙方式二
"order_by": text("-create_time")
}
2. 限制查询
2.1 limit
可以限制每次查询的时候只查询几条数据。例如:查询前10条
session.query(Article).limit(10).all()
2.2 offset
可以限制查找数据的时候过偏移条。例如:从第10条开始取10条
session.query(Article).offset(10).limit(10).all()
2.3 slice
可以对Query对象使用切片操作,来获取想要的数据。例如:获取时间排序的后10条
session.query(Article).order_by(Article.create_time.desc()).slice(0,10).all()
# 列表切片的方式获取,后缀不需要加all()
session.query(Article).order_by(Article.create_time.desc())[0:10]
3. 懒加载
当我们通过外键查询的时候不是直接获取相对应的数据,而是返回一个类似于Query的对象,这样我们就可以继续进行相应的条件过滤。
那么这时候就可以考虑使lazy='dynamic'
,其返回的是AppenderQuery
对象了,这个对象继承Query
因此拥有Query
所有的过滤方法
lazy
可用的选项:
select
:这个是默认选项。还是拿user.articles
的例子来讲。如果你没有访问user.articles
这个属性,那么sqlalchemy就不会从数据库中查找文章。一旦你访问了这个属性,那么sqlalchemy就会立马从数据库中查找所有的文章,并把查找出来的数据组装成一个列表返回。这也是懒加载。dynamic
:在访问user.articles
的时候返回回来的不是一个列表,而是AppenderQuery
对象。
class Article(Base):
......
# 一般懒加载用于一查多,因此定义在反向查询中
author = relationship("User",backref=backref("articles",lazy="dynamic"))
4. 分组查询、过滤、连接和子查询
4.1 group_by
根据某个字段进行分组。比如想要根据性别进行分组,来统计每个分组分别有多少人。
session.query(User.gender,func.count(User.id)).group_by(User.gender).all()
>>>[('male',2),('female',1)]
4.2 having
having是对查找结果进一步过滤。比如只想要看未成年人的数量,那么可以首先对年龄进行分组统计人数,然后再对分组进行having过滤。
session.query(User.age,func.count(User.id)).group_by(User.age).having(User.age >= 18).all()
4.3 join
join分为left join(左外连接)和right join(右外连接)以及内连接(等值连接)
比如现在要实现一个功能,要查找所有用户,按照发表文章的数量来进行排序。
session.query(User,func.count(Article.id)).join(Article).group_by(User.id).order_by(func.count(Article.id).desc()).all()
4.4 subquery
子查询可以让多个查询变成一个查询,只要查找一次数据库,性能相对来讲更加高效一点
那么在sqlalchemy中,要实现一个子查询,应该使用以下几个步骤:
- 将子查询按照传统的方式写好查询代码,然后在
query
对象后面执行subquery
方法,将这个查询变成一个子查询。 - 在子查询中,将以后需要用到的字段通过
label
方法,取个别名。 - 在父查询中,如果想要使用子查询的字段,那么可以通过子查询的返回值上的
c
属性拿到。
sq = session.query(User.city.label("city"),User.age.label("age")).filter(User.username=='xxx').subquery()
session.query(User).filter(User.city==sq.c.city,User.age==sq.c.age).all()