У меня есть сопоставленный класс с методом @reconstructor, который создает словарь поиска из отношений с этим классом. Это работает. Он вызывается в init (явно), затем также вызывается sqlalchemy при восстановлении из базы данных и отображает связанные «соединения» каждого экземпляра на self.compound, так что self.compound ['составное_имя '] извлекает соединение с таким именем из соответствующего поля self.compounds. Он работает в постоянном времени, в отличие от предыдущего линейного поиска собственных значений. Это здорово ...
@reconstructor
def _create_lookup(self):
print('Create lookup called.')
attr = getattr(self, 'compounds')
lookup = dict(zip(
[getattr(c, 'name') for c in attr],
[getattr(c, '', c) for c in attr]
))
setattr(self, 'compound', lookup)
Однако , более общая форма ниже не работает при использовании в качестве декоратора классов (я хочу это, потому что это поведение желательно для нескольких моих классов , но не обязательно наследуется хорошо):
def give_class_lookup_on_attr(attr_to_lookup, lookup_key_attr, lookup_value_attr, lookup_name):
# None is a key for the lookup_value_attr to return the object itself (set in the default)
if lookup_value_attr is None:
lookup_value_attr = ''
# passing an empty string will never find an attribute, which makes it the key for returning the default
print('give_class_... decorator called.')
def class_wrap(cls):
@reconstructor
def func(self):
print('Create lookup called.')
attr = getattr(self, attr_to_lookup)
lookup = dict(zip(
[getattr(c, lookup_key_attr) for c in attr],
[getattr(c, lookup_value_attr, c) for c in attr]
# return the object as the value in dict if attr is not present
))
setattr(self, lookup_name, lookup)
cls._create_lookup = func
print('reconstructor method added to cls and cls returned')
return cls
return class_wrap
По инструкциям печати, я смог подтвердить, что когда я вызываю декоратор в моем классе с соответствующими параметрами, реконструктор создается на класс, но никогда не называется. Я также проверил флаг класса .__ sa_reconstructor__, который имеет значение True (единственное, что декоратор-декоратор делает с методом). Но он по-прежнему не вызывается.
Поскольку декоратор класса вызывается после создания класса, а затем класс передается, мое рабочее предположение состоит в том, что преобразователь sqlalchemy имеет уже выполнено, это работает (вот почему это работает, когда выполняется внутри класса, но не с декоратором класса), поэтому он никогда не находит метод реконструкции с добавлением декоратора.
Итак, мое предположение о правильный путь, и есть ли способы обновить маппер sqlalchemy, чтобы он выглядел вторично? Или я должен начать смотреть на написание и / или добавление своих собственных слушателей событий sqlalchemy (при условии, что у них не будет той же самой проблемы).
РЕДАКТИРОВАТЬ: мое предположение кажется дополнительно подтверждается:
mapper = class_mapper(MyMappedClass)
print(mapper._reconstructor)
Если я вызову выше в моих тестах с моим встроенным объявлением метода, он возвращает реконструктор (функция MyMappedClass._create_lookup в 0x7f452a49e8c8), но возвращает None при использовании моего декоратора класса.