SQLAlchemy的db.session.query()与model.query有何区别?

30

对于简单的返回所有结果查询,是否应该优先选择一种方法?我在网上找到了两种用途,但实际上找不到任何描述它们之间差异的内容。

db.session.query([my model name]).all()

[my model name].query.all()

我认为 [我的模型名称].query.all() 更具描述性。


8
请访问 https://dev59.com/p2ct5IYBdhLWcg3wF5tF。区分SQLAlchemy中的Model.query和Session.query(Model)的区别是什么? - alecxe
我更喜欢后者,除非您只需要从模型中选择特定列的情况。在这种情况下,请执行db.session.query(Model.column_1, Model.column_2).all()。 - Lyman Zerga
1个回答

18

回答这个问题存在很高的主观性,很难给出清晰的答案。

从一个角度来看,db.session是更好的选择,因为第二种方法需要将它作为额外步骤纳入到您的模型中——它不是Base类的默认部分。例如:

Base = declarative_base()
DBSession = scoped_session(sessionmaker())
class User(Base):
   __tablename__ = 'users'

   id = Column(Integer, primary_key=True)
   name = Column(String)
   fullname = Column(String)
   password = Column(String)
session = Session()
print(User.query)

这段代码出现了以下错误:

AttributeError: 类对象 'User' 没有属性 'query'

你需要进行类似下面的操作:

class User(Base):
   __tablename__ = 'users'

   id = Column(Integer, primary_key=True)
   name = Column(String)
   fullname = Column(String)
   password = Column(String)
   query = DBSession.query_property()

然而,也可以说仅因其未默认启用,并不能将其作为一种不合理的发起查询方式而使其失效。此外,在 flask-sqlalchemy 包中(该包简化了 sqlalchemy 集成到 flask web 框架中的操作),这已经在 Model 类的一部分(文档)中为您完成。将查询属性添加到模型中还可以在 sqlalchemy 教程(文档)中看到:

class User(object):
   query = db_session.query_property()
   ....

因此,人们可以争论采用哪种方法。

当我从单个表中进行选择时,我个人更喜欢第二种方法。例如:

serv = Service.query.join(Supplier, SupplierUsr).filter(SupplierUsr.username == usr).all()

这是因为它具有较短的行长度,仍然容易阅读。

如果我从多个表中选择或指定列,则会使用模型查询方法,因为它可以从多个模型中提取信息。

deliverables = db.session.query(Deliverable.column1, BatchInstance.column2).\
    join(BatchInstance, Service, Supplier, SupplierUser). \
    filter(SupplierUser.username == str(current_user)).\
    order_by(Deliverable.created_time.desc()).all()

话虽如此,还可以提出一个反对意见,即始终使用 session.query 方法,因为它使代码更加一致,在从左到右阅读时,读者能够立刻知道他们将要读取的 sqlalchemy 指令是查询 query,然后再吸收涉及的表和列。

归根结底,你的问题的答案是主观的,没有正确的答案,无论哪种方式,任何代码可读性方面的益处都很小。我唯一看到有强烈好处的事情是,如果您从许多表中进行选择,请勿使用模型查询,而是使用 session.query 方法。


你如何将两者结合起来呢?我的意思是,Model.query 使用 DBSession,它只被实例化一次,就像 DBSession = scoped_session(SessionLocal)。但是我还有一些辅助方法在 BaseMixin 中(例如:insert、update、delete),在这种情况下,会传入一个会话参数,所以我必须创建一个新的会话。所以,如果通过 Model.query 进行查询并尝试使用我的辅助方法,它会出错,因为该对象已经分配给另一个会话了。有什么想法吗? - lowercase00

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接