SQLAlchemy:运算符 LIKE 和自定义类型

SQLAlchemy: operator LIKE and custom types

我使用 sqlalchemy ORM。我有以下自定义列类型和 table-映射 class:

class JSONEncodedDict(TypeDecorator):
    impl = VARCHAR

    def process_bind_param(self, value, dialect):
        if value is not None:
            value = json.dumps(value)

        return value

    def process_result_value(self, value, dialect):
        if value is not None:
            value = json.loads(value)
        return value

Base = declarative_base()
class Task(Base):
    __tablename__ = 'tasks'

    id = Column(INT, primary_key=True)
    description = Column(JSONEncodedDict)
    created = Column(TIMESTAMP)
    updated = Column(TIMESTAMP)

我想使用运算符 'like':

查询对象
tasks = session.query(Task).filter(Task.description.like("%some pattern%")).all()

但据我所知,方法 process_bind_param 还转换了 like 运算符的参数。所以在 sql 跟踪中我看到

...WHERE description LIKE '"%some pattern%"'

而不是

...WHERE description LIKE '%some pattern%'

所以没有匹配的行。

如何按照我想要的方式使用 LIKE 运算符执行查询?

可以使用 literal():

绕过自动类型处理(或使用 type_ 参数强制你自己处理)
Task.description.like(literal("%some pattern%"))

另一种方法是在尝试使用像 like 这样的运算符之前,使用 cast()type_coerce() 将列强制 为文本形式, contains 或其他:

from sqlalchemy import type_coerce, String

stmt = select([my_table]).where(
    type_coerce(my_table.c.json_data, String).like('%foo%'))

或者您可以在自定义类型 class 定义中执行此操作:

from sqlalchemy.sql import operators
from sqlalchemy import String

class JSONEncodedDict(TypeDecorator):

    impl = VARCHAR

    def coerce_compared_value(self, op, value):
        if op in (operators.like_op, operators.notlike_op):
            return String()
        else:
            return self

    def process_bind_param(self, value, dialect):
        if value is not None:
            value = json.dumps(value)

        return value

    def process_result_value(self, value, dialect):
        if value is not None:
            value = json.loads(value)
        return value

参考:doc