SQLALchemy 使用来自 kwargs 的 in 子句进行更新

SQLALchemy update with in clause from kwargs

我正在尝试编写一个将 kwargs 作为参数的函数,并且 生成更新语句,其中要更新的行是 在 in 子句中指定。

这是我的资料:

    def update_by_in(self, **kwargs):
        filter_group = []
        for col in kwargs['query_params']:
            attr = getattr(self.model_class, col)
            filter_group.append(attr.in_(tuple(kwargs['query_params'][col])))
        self._session.query(self.model_class).\
            filter(*filter_group).\
            update(kwargs['values'])


    self.update_by_in(
        **{'query_params': {'companyCode': ['A', 'B', 'C']},
           'values': {'portfolioName': 'test'}}
     )

sqlalchemy.orm.evaluator.UnevaluatableError: Cannot evaluate clauselist with operator <function comma_op at 0x7f33f037adc0>

为了验证查询部分是否正常工作,我从

打印了 return
self._session.query(self.model_class).filter(*filter_group).all()

[<common.models_dec_core.Portfolio object at 0x7f2b98157f40>]

也尝试对传递给更新的字典进行硬编码,但得到了同样的错误。

我做错了什么?

我通过将 synchronize_session='fetch' 添加到 更新。真的很想知道为什么需要 - 我有 类似的代码,但不使用变量(模型和列 是硬编码的)并且在没有 synchronize_session.

的情况下也能工作

sqlalchemy 1.4.2 不会出现此问题,但 sqlalchemy 1.3.16 会出现此问题。

我认为这是因为默认的 synchronize_session 值是 "evaluate" 并且它无法解决 1.3.16 中的 in_ 条件。

以下使用 or_ 的条件使用默认值,但使用 in_ 的条件需要将 synchronize_session 设置为 "fetch"

示例 or_in_


from datetime import datetime, date
from sqlalchemy import (
    create_engine,
    Text,
    Integer,
    String,
    ForeignKey,
    UniqueConstraint,
    update,
    DateTime,
   Date,
    Boolean,
    LargeBinary,
)
from sqlalchemy.schema import (
    Table,
    Column,
    MetaData,
)
from sqlalchemy.sql import select, and_, or_, func
from sqlalchemy.orm import relationship
from sqlalchemy.orm import Session
from sqlalchemy.exc import IntegrityError
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()


engine = create_engine("sqlite://", echo=False)


class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    name = Column(String(100), nullable=False)
    code = Column(String(1), nullable=False)
    portfolio = Column(String(100), nullable=True)


Base.metadata.create_all(engine)
def update_by_or(session, model_class, **kwargs):
    filter_group = []
    for col in kwargs['query_params']:
        attr = getattr(model_class, col)
        filter_group.append(or_(*[attr == v for v in kwargs['query_params'][col]]))
    session.query(model_class).\
        filter(filter_group[0]).\
    update(kwargs['values'])


def update_by_in(session, model_class, **kwargs):
    filter_group = []
    for col in kwargs['query_params']:
        attr = getattr(model_class, col)
        filter_group.append(attr.in_(kwargs['query_params'][col]))
    session.query(model_class).\
        filter(filter_group[0]).\
    update(kwargs['values'], synchronize_session='fetch')

def print_users(session):
    for u in session.query(User).all():
        print (u.id, u.name, u.code, u.portfolio)

session = Session(engine)

session.add(User(name='One', code='A'))
session.add(User(name='Two', code='B'))
session.add(User(name='Three', code='C'))
session.add(User(name='Four', code='D'))
session.commit()
print_users(session)
update_by_in(session, User, **{'query_params': {'code': ['A', 'B', 'C']},
   'values': {User.portfolio: 'test1'}})
session.commit()
print_users(session)
update_by_in(session, User, **{'query_params': {'code': ['A', 'B', 'C']},
   'values': {User.portfolio: 'test2'}})
session.commit()
print_users(session)

输出

1 One A None
2 Two B None
3 Three C None
4 Four D None
1 One A test1
2 Two B test1
3 Three C test1
4 Four D None
1 One A test2
2 Two B test2
3 Three C test2
4 Four D None

虽然我收到的异常是:

sqlalchemy.exc.InvalidRequestError: Could not evaluate current criteria in Python: "Cannot evaluate clauselist with operator <function comma_op at 0x7f7c082821e0>". Specify 'fetch' or False for the synchronize_session parameter.