Уведомления

Группа в Telegram: @pythonsu

#1 Июнь 14, 2017 00:04:36

Stright
От: Кострома
Зарегистрирован: 2015-01-20
Сообщения: 139
Репутация: +  16  -
Профиль   Отправить e-mail  

Вопрос по sqlalchemy.Column

Всем здравствуйте!
Пишу сохранение истории изменения значений атрибутов модели алхимии. Перечень атрибутов, которые важны для истории, сохраняю в атрибуте класса history_attributes, при этом в целях удобства рефакторинга использую не строковые названия атрибутов, а сами дескрипторы.

 from sqlalchemy import Integer, Column, String
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class HistoryAttribute:
    def __init__(self, descriptor, display_name, use_message=False):
        self.name = descriptor.name
        self.display_name = display_name
        self.use_message = use_message
class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)
    first_name = Column(String(100))
    email = Column(String(100))
    history_attributes = (
        HistoryAttribute(descriptor=first_name, display_name='User name'),
        email
    )
print(User.history_attributes[0].name)
>>> None
print(User.history_attributes[1].name)
>>> email
Почему пропадает атрибут name экземпляра Column, если дескриптор передавать в качестве аргумента в конструктор другого класса? Конечно, можно написать first_name = Column('first_name', String(100)), но хочется единообразия, потому как нигде в приложении я не передаю явно name в конструктор Column.
Пока проблему обошел заменив в history_attributes HistoryAttribute на namedtuple, который уже потом и передаю в конструктор класса HistoryAttribute, но это как то сильно похоже на костыль

Отредактировано Stright (Июнь 14, 2017 00:18:39)

Офлайн

#2 Июнь 15, 2017 06:13:25

PooH
От:
Зарегистрирован: 2006-12-05
Сообщения: 1948
Репутация: +  72  -
Профиль   Отправить e-mail  

Вопрос по sqlalchemy.Column

А у него в этот момент еще не установлено значение для name. Оно появляется после цепочки
DeclarativeMeta.__init__
_as_declarative
_MapperConfig.setup_mapping
_MapperConfig.__init__
_extract_declared_columns
_undefer_column_name - вот тут имя атрибута класса отдается в дескриптор.
А экземпляр HistoryAttribute инициализируется до вызова DeclarativeMeta.__init__. Можно вот так

  
class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)
    first_name = Column(String(100))
    email = Column(String(100))
 
User.history_attributes = (
        HistoryAttribute(descriptor=User.first_name, display_name='User name'),
        User.email
    )
или наследоваться от DeclarativeMeta, сделать в нем передачу в HistoryAttribute имен после того как их получили дескрипторы и передать declarative_base свой класс в параметре metaclass



Вот здесь один из первых отарков съел лаборанта. Это был такой умный отарк, что понимал даже теорию относительности. Он разговаривал с лаборантом, а потом бросился на него и загрыз…

Отредактировано PooH (Июнь 15, 2017 06:16:46)

Офлайн

#3 Июнь 15, 2017 09:54:54

Stright
От: Кострома
Зарегистрирован: 2015-01-20
Сообщения: 139
Репутация: +  16  -
Профиль   Отправить e-mail  

Вопрос по sqlalchemy.Column

Спасибо большое за помощь и подробный ответ! Примерно то же самое мне ответили на stackoverflow, оставил такой вариант:

 class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)
    first_name = Column(String(100))
    email = Column(String(100))
    @classmethod
     def get_history_attributes(cls):
        return (
            HistoryAttribute(descriptor=cls.first_name, display_name='User name'),
            cls.email
        )

Отредактировано Stright (Июнь 15, 2017 09:56:52)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version