SQLAlchemy не обновляет модель, игнорирует все измененные поля, кроме последнего измененного - PullRequest
0 голосов
/ 13 февраля 2020

У меня есть следующая модель:

class Model(db.Base):
    """Table for storing snapshots of Projects health."""
    __tablename__ = 'my_table'

    id = Column(Integer(), primary_key=True)
    first_attribute = Column(Integer)
    second_attribute = Column(Integer)
    created_at = Column(DateTime)

Мне нужно обновить атрибуты существующего объекта. Вот что происходит:

ipdb> model = (
    db.session.query(Model)
    .filter(id=5908)
    .first()
)

ipdb> logging.getLogger('sqlalchemy.engine').setLevel(logging.DEBUG)
ipdb> model.first_attribute
1
ipdb> model.second_attribute
1
ipdb> model.first_attribute = object.some_value
ipdb> model.second_attribute = object.another_value
ipdb> model.created_at = get_utc_now()
ipdb> model.first_attribute
0
ipdb> model.second_attribute
0
ipdb> db.session.add(model)
ipdb> db.session.commit()
ipdb> model.first_attribute
1
ipdb> model.second_attribute
1

Итак, модель изначально имела значение 1, которое было изменено на 0, и после его фиксации оно остается равным 1. Как и значение в базе данных.

На самом деле оператор debug признает, что ему не нужны first_attribute или second_attribute, и он только обновляет created_at:

2020-02-13 10:55:29,133 - sqlalchemy.engine.base.Engine - INFO - BEGIN (implicit)
2020-02-13 10:55:29,137 - sqlalchemy.engine.base.Engine - INFO - UPDATE my_table SET created_at=%(created_at)s WHERE my_table.id = %(id)s
2020-02-13 10:55:29,138 - sqlalchemy.engine.base.Engine - INFO - {'created_at': datetime.datetime(2020, 2, 13, 9, 54, 9, 610208, tzinfo=tzutc()), 'id': 5908}
2020-02-13 10:55:29,345 - sqlalchemy.engine.base.Engine - INFO - COMMIT

Интересный факт заключается в том, что только обновленное поле является последним измененным перед добавлением модели в сеанс. Я поменял местами присваивания значений model.created_at и model.first_attribute, оставив этот второй как последний перед db.session.add(model), и он действительно обновляется (опять же, только этот обновляется).

1 Ответ

1 голос
/ 13 февраля 2020

Я мог бы сделать эту работу, используя db.session.merge(model) вместо db.session.add(model).

Похоже, по какой-то причине я до сих пор не понимаю, что экземпляр model не был в рамках сеанса , merge копирует состояние данного экземпляра в тот, который находится внутри сеанса, на основе атрибутов первичного ключа (вам все еще нужно зафиксировать транзакцию, чтобы сохранить изменения в БД).

Документация по SQLAlchemy на это: https://docs.sqlalchemy.org/en/13/orm/session_api.html#sqlalchemy .orm.session.Session.merge

...