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

时间:2015-02-10 18:24:56

标签: python postgresql orm sqlalchemy

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

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)

我想使用operator' like':

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

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

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

而不是

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

所以没有匹配的行。

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

2 个答案:

答案 0 :(得分:3)

使用literal()可以绕过自动类型处理(或使用type_参数强制自己):

Task.description.like(literal("%some pattern%"))

答案 1 :(得分:1)

另一种方法是在尝试使用cast()type_coerce()之类的运算符之前,先使用likecontains 强制将该列转换为文本或其他内容:

from sqlalchemy import type_coerce, String

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

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

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

ref:doc