SQLAlchemy类型装饰器失败,`对象没有属性'self_group'`

时间:2018-05-01 15:44:30

标签: python sqlalchemy

我有一个使用SQLAlchemy 1.1的遗留Python 3代码库,出于“原因”,它有一个类:

class jsonbool(str):
   def __bool__(self):
       return True if self == 'true' else False

此类用于SQLAlchemy过滤器表达式,例如query.filter(SomeTable.ABooleanColumn == anInstanceOfjsonbool).all()。这在1.1中运行良好,因为使用了jsonbool类型的字符串表示形式(例如truefalse)。

在SQLAlchemy 1.2中,他们一边增加了额外的检查,以防止某些类型的伪装成为布尔值。现在上面的工作失败了sqlalchemy.exc.StatementError: (builtins.TypeError) Not a boolean value: 'false'false实际上有一个jsonbool的实例。

我想用SQLAlchemy TypeDecorator来解决这个问题,这允许我在表达式中绑定时将参数转换为布尔值。我的原型只是为了让自定义类型装饰起作用:

import sqlalchemy.types as types

class jsonbool(str, types.TypeDecorator):
   impl = types.Boolean

   def __bool__(self):
       return True if self == 'true' else False

唉,这个以及我尝试的所有类似内容在尝试运行查询时会导致AttributeError: 'Boolean' object has no attribute 'self_group'(其中s/Boolean/WhateverImplIPick)。我也尝试使用UserDefinedType,结果相同。

当我将jsonbool类型用作SQLAlchemy表达式的一部分时,如何更改JoinHandle类型的行为?

1 个答案:

答案 0 :(得分:2)

TypeDecorator是SQLAlchemy类型,类似于StringBoolean,其实例用于声明列或表达式的类型,如

foo = Column(String, ...)
bar = Column(jsonbool, ...)

将这样的类型用作值是没有意义的,因此就像strString分开的那样,您需要一个与JsonBool分开的jsonbool类,就像这样:

class JsonBool(TypeDecorator):
    impl = Boolean

    def process_bind_param(self, value, dialect):
        return value == "true"

    def process_result_value(self, value, dialect):
        return jsonbool("true") if value else jsonbool("false")

当然,您需要更改SomeTable.ABooleanColumn的定义才能使用此类型:

ABooleanColumn = Column(JsonBool, ...)

这可能是您的代码库的高级订单,在这种情况下,您可以使SQLAlchemy对jsonbool个对象执行custom compilation

class jsonbool(str, ColumnElement):
    def __bool__(self):
        return True if self == 'true' else False

@compiles(jsonbool)
def _compile_jsonbool(element, compiler, **kwargs):
    if element:
        return compiler.visit_true(None)
    else:
        return compiler.visit_false(None)