Flask-SQLAlchemy 中的 SQLAlchemy 2.0 版本 User.query.get(1)?

Pat*_*ell 17 sqlalchemy flask flask-sqlalchemy

问题

该Query.get()方法在 SQLAlchemy 2.0 中已弃用。因此,Flask-SQLAlchemy 查询接口被认为是遗留的。因此,User.query.get(1)在我的 Flask-SQLAlchemy 项目中运行会出现如下所示的遗留警告:

>>> User.query.get(1)
<stdin>:1: LegacyAPIWarning: The Query.get() method 
is considered legacy as of the 1.x series of SQLAlchemy 
and becomes a legacy construct in 2.0. The method is 
now available as Session.get() (deprecated since: 2.0) 
(Background on SQLAlchemy 2.0 at: https://sqlalche.me/e/b8d9)
<User spongebob>
Run Code Online (Sandbox Code Playgroud)

我的问题

Flask-SQLAlchemy 中新的 SQLAlchemy 2.0 兼容版本是什么User.query.get(1)?更具体地说,为什么 Flask-SQLAlchemy 文档推荐下面的方法 #2,尽管根据我对 SQLAlchemy 2.0 迁移指南的阅读,方法 #1 似乎是新版本?

方法#1:db.session.get(User, 1)

第一种方法来自 SQLAlchemy 文档,特别是SQLAlchemy 2.0 迁移 - ORM 使用指南。将该指南中的“2.0 样式”示例转换为我的 Flask-SQLAlchemy 项目会生成以下代码,该代码运行良好:

>>> db.session.get(User, 1)
<User spongebob>
Run Code Online (Sandbox Code Playgroud)

session.get()据我所知,Flask-SQLAlchemy 3.0.x 文档中没有提到这种方法,除了在get_or_404.

方法#2:db.session.execute(db.select(User).filter_by(id=1)).scalar()

这种方法来自Flask-SQLAlchemy 文档,该文档建议使用session.execute(select(...))作为旧版Model.query和的替代品session.query。这也很好用:

>>> db.session.execute(db.select(User).filter_by(id=1)).scalar()
<User spongebob>
Run Code Online (Sandbox Code Playgroud)

方法#1 与方法#2 与传统方法

方法 #1 ( db.session.get(User, 1)) 似乎与旧方法 ( User.query.get(1)) 最相似,因为它会在第一次运行时缓存结果session,并且不会对数据库发出不必要的额外调用。这可以在打开 echo 的 REPL 中看到,即db.engine.echo = True。相反,方法 #2 ( session.execute(select(...))) 每次都会按预期访问数据库。

我的设置/环境

  1. 版本:Python 3.11 虚拟环境中的 Flask 2.2.2、Flask-SQLAlchemy 3.0.3 和 SQLAlchemy 2.0.1。

  2. 我正在使用 Flask Mega-Tutorial 中定义的项目结构,特别是Part IV Database。

小智 15

将 all 替换Model.query.get(id)为db.session.get(Model, id)是可怕且不优雅的:明显丧失可读性。

我们需要更好的解决方案!


小智 11

根据https://docs.sqlalchemy.org/en/14/changelog/migration_20.html#orm-query-get-method-moves-to-session

Query.get() 方法仍然用于遗留目的,但主要接口现在是 Session.get() 方法:

# legacy usage
user_obj = session.query(User).get(5)
Run Code Online (Sandbox Code Playgroud)

迁移到2.0

在1.4/2.0中,Session对象增加了一个新的Session.get()方法:

# 1.4 / 2.0 cross-compatible use
user_obj = session.get(User, 5)
Run Code Online (Sandbox Code Playgroud)

与flask_sqlalchemy兼容,这应该可以很好地工作

user_obj = db.session.get(User, 5)
Run Code Online (Sandbox Code Playgroud)


小智 0

使用带有用户注册的 Flask 应用程序时,我遇到了这个问题。Flask登录文档有一个示例,有一个小错误:

@login_manager.user_loader
def load_user(user_id):
    return User.get(user_id)
                ^^^ not correct
Run Code Online (Sandbox Code Playgroud)

所以,我把它改成了:

@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))
                ^^^^^^^^^ deprecated
Run Code Online (Sandbox Code Playgroud)

最后,我使用了方法#1,一切都很顺利:

@login_manager.user_loader
def load_user(user_id):
    return db.session.get(User, int(user_id))
Run Code Online (Sandbox Code Playgroud)