我有一个使用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
类型的字符串表示形式(例如true
或false
)。
在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
类型的行为?
答案 0 :(得分:2)
TypeDecorator
是SQLAlchemy类型,类似于String
或Boolean
,其实例用于声明列或表达式的类型,如
foo = Column(String, ...)
bar = Column(jsonbool, ...)
将这样的类型用作值是没有意义的,因此就像str
与String
分开的那样,您需要一个与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)