为何SQLAlchemy部分ORM方法(如filter_by)不返回可打印列表?
为什么
filter_by返回BaseQuery对象而不是实例/列表? 这完全是正常行为,别担心!这其实是SQLAlchemy ORM查询系统的核心设计——惰性查询导致的,我来给你拆解清楚:
1. 查询方法的两类角色
SQLAlchemy的查询方法分为两种:
- 构建查询的方法:比如
filter_by、filter、order_by、limit这些,它们的作用只是组装查询条件/规则,并不会立刻去数据库执行查询。所以它们返回的是BaseQuery对象,这个对象就像一个"查询蓝图",记录了你想要怎么查数据,但还没真正去数据库捞数据。 - 触发执行的方法:比如
all()、first()、one()、scalar()这些,调用它们才会真正把之前组装好的查询发送给数据库,获取结果并返回:all():执行查询,返回所有匹配结果的列表(即使只有一个结果,也是列表)first():执行查询,返回结果集中的第一个实例(没有匹配则返回None)one():执行查询,要求结果集恰好有一个匹配,否则抛出异常
2. 结合你的代码看差异
你写的三个查询:
Person.query.all():直接触发查询,返回所有Person实例的列表,因为all()是执行方法Person.query.first():触发查询,返回第一个实例,first()也是执行方法Person.query.filter_by(name='Amy'):只是组装了"按name等于Amy过滤"的查询条件,没有触发执行,所以返回BaseQuery对象
如果想要拿到Amy的实例,你需要在后面加上执行方法,比如:
# 返回所有name为Amy的实例列表 Person.query.filter_by(name='Amy').all() # 返回第一个name为Amy的实例 Person.query.filter_by(name='Amy').first()
3. 为什么要设计成惰性查询?
这种设计的好处是可以链式组装复杂查询,比如你可以先过滤,再排序,再限制数量,最后才执行:
# 先组装查询:找name含"A"的人,按id倒序,取前3个 query = Person.query.filter(Person.name.contains("A")).order_by(Person.id.desc()).limit(3) # 最后执行查询,拿到结果 results = query.all()
如果每一步都立刻执行查询,那性能会差很多,而且也没法灵活组合查询条件。
另外,你给Person类定义了__repr__方法,所以当你打印all()或first()的结果时,会看到友好的<Person Id: ...>字符串,而BaseQuery对象的默认__repr__就是显示它的类和内存地址,这就是你看到<flask_sqlalchemy.Basequery object at 0xsadfjasdfsd>的原因。
内容的提问来源于stack exchange,提问作者Yukai Wang
相关产品推荐
相关产品推荐

