Принятие нескольких типов в поле модели SQLAlchemy - PullRequest
0 голосов
/ 05 ноября 2018

Рассмотрим модель SQLAlchemy с полем String:

class MyModel(Base):
    name = Column(String(100))
    # ...

Как правильно принять это поле, например, int значений и преобразовать их в строки перед сохранением и запросом - по сути str(val)?

В конце концов я хочу, чтобы все это было эквивалентно:

m = MyModel(name='123')
m = MyModel(name=123)
q = session.query(MyModel).filter_by(name='123')
q = session.query(MyModel).filter_by(name=123)

1 Ответ

0 голосов
/ 05 ноября 2018

Я тестировал на MySQL, и ваш оригинальный код работает так:

class MyModel(Base):

    __tablename__ = 'mymodel'

    id = Column(Integer, primary_key=True)
    name = Column("name", String(100))

if __name__ == '__main__':
    Base.metadata.drop_all(engine)
    Base.metadata.create_all(engine)
    s = Session()
    new_obj = MyModel(name=123)
    print(type(new_obj.name))  # <class 'int'>
    s.add(new_obj)
    s.commit()
    s.close()

    s = Session()
    obj = s.query(MyModel).filter(MyModel.name == 123).one()  # query with integer value
    print(obj.name, type(obj.name))  # 123 <class 'str'>

В Этот ответ , относящийся к проверке и приведению типов данных @zzzeek, ​​говорит, что sqlalchemy:

... относится к базе данных DBAPI / как к лучшему и наиболее эффективному источнику валидации и приведения значений.

В этом ответе также подробно описан один способ использования системы SQLAlchemy Event для перехвата данных, установленных в инструментированных атрибутах, и выполнения каких-либо действий.

Другим способом будет использование декоратора hybrid_property и связанного с ним setter для выполнения действий по присвоению значений атрибутам по мере их установки. Он обрабатывает как новые объекты, так и запросы:

from sqlalchemy.ext.hybrid import hybrid_property

class MyModel(Base):

    __tablename__ = 'mymodel'

    id = Column(Integer, primary_key=True)
    name_ = Column("name", String(100))

    @hybrid_property
    def name(self):
        return self.name_

    @name.setter
    def name(self, val):
        self.name_ = str(val)

if __name__ == '__main__':
    Base.metadata.drop_all(engine)
    Base.metadata.create_all(engine)
    s = Session()
    new_obj = MyModel(name=123)
    print(type(new_obj.name))  # <class 'str'>
    s.add(new_obj)
    s.commit()
    s.close()

    s = Session()
    obj = s.query(MyModel).filter(MyModel.name == 123).one()  # query with integer value
    print(obj.name, type(obj.name))  # 123 <class 'str'>

Все эти методы хорошо документированы и поэтому могут считаться «правильными».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...