Декоратор типа SQLAlchemy завершается с ошибкой "объект не имеет атрибута" self_group "

У меня есть устаревшая кодовая база 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?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
1 323
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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)

Похоже, я совершенно неправильно понял понятие Type / TypeDecorator. Огромное спасибо!

Adam Wright 02.05.2018 12:10

Другие вопросы по теме