Декоратор типа SQLAlchemy завершается с ошибкой `у объекта нет атрибута 'self_group'` - PullRequest
0 голосов
/ 01 мая 2018

У меня есть устаревшая кодовая база Python 3 с использованием SQLAlchemy 1.1, которая по «причинам» имеет класс:

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?

1 Ответ

0 голосов
/ 02 мая 2018

A 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 объектов:

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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...