首页 > 解决方案 > SAWarning:评估非映射列表达式

问题描述

这几天一直在测试sqlalchemy,在ORM模式下使用update方法遇到了一些问题。

我基本上想做的是根据对第二个表执行的子查询的结果更新表。

这是一个简化的示例:

from sqlalchemy import create_engine, Column, Integer, Float, Boolean
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import Session

Base = declarative_base()
engine = create_engine('postgresql+psycopg2://urldb', echo=True)
session = Session(engine)

class User1(Base):
    __tablename__ = 'user1'
    index = Column(Integer, primary_key=True)
    value1 = Column(Float)
    value2 = Column(Boolean)


class User2(Base):
    __tablename__ = 'user2'
    index = Column(Integer, primary_key=True)
    value1 = Column(Float)
    value2 = Column(Boolean)

try:
    User1.__table__.drop(engine)
    User2.__table__.drop(engine)
    Base.metadata.create_all(engine)
except:
    Base.metadata.create_all(engine)


user1 = User1(value1=12, value2=True)
user2 = User1(value1=15, value2=True)
user3 = User1(value1=7, value2=True)
user4 = User2(value1=12, value2=True)
user5 = User2(value1=15, value2=False)

session.add(user1)
session.add(user2)
session.add(user3)
session.add(user4)
session.add(user5)

session.flush()
session.commit()

stmt = session.query(User2).filter(User2.value1 > 12).subquery()

session.query(User1).filter(User1.value1 == stmt.c.value1).update({User1.value2 : stmt.c.value2})
session.commit()

我希望value2user2更新到False,该代码正确。但是,我收到以下警告消息。据我了解,更新会期望一些类似 ORM 的表达式而不是 stmt.c。但是我看不到如何将我的 stmt 对象转换为 ORM 对象(尝试别名为 User1 但失败了,后来我明白了为什么......)。

有什么想法可以绕过该警告消息吗?提前致谢!

/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/sqlalchemy/orm/evaluator.py:71:SAWarning:评估非映射列表达式'%(4357770376 anon)s.value1 ' 到 ORM 实例上;这是一个已弃用的用例。请使用 ORM 评估的 UPDATE / DELETE 表达式中的实际映射列。“更新/删除表达式。” % 子句)/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/sqlalchemy/orm/evaluator.py:71:SAWarning:评估非映射列表达式'%(4357770376 anon) s.value2' 到 ORM 实例上;这是一个已弃用的用例。请使用 ORM 评估的 UPDATE / DELETE 表达式中的实际映射列。“更新/删除表达式。” % 子句)

标签: python-3.xsqlalchemy

解决方案


子查询声明不是必需的。您可以直接update from在 1.4 版上:

from sqlalchemy import update

session.execute(
    update(User1).values(
        value2=User2.value2
    )
    .where(User1.value1==User2.value1, User2.value1 > 12)
    .execution_options(synchronize_session="fetch") # won't work with 'evaluate'
)
session.commit()
# UPDATE user1 SET value2=(SELECT user2.value2 
# FROM user2 
# WHERE user1.value1 = user2.value1) WHERE user1.value1 > %(value1_1)s 
# RETURNING user1.index

您必须将 设置execution_options为不引发错误。

另一个选项涉及仅针对值的相关子查询:

from sqlalchemy import select, update

session.execute(
    update(User1).values(
        value2=select(User2.value2).\
                where(User1.value1 == User2.value1).\
                scalar_subquery()
    )
    .where(User1.value1 > 12)
)
session.commit()
# UPDATE user1 SET value2=user2.value2 
# FROM user2 WHERE user1.value1 = user2.value1 AND user2.value1 >= %(value1_1)s 
# RETURNING user1.index

但随后update where条件必须适用于User1


推荐阅读