Почему в БД не обновляется запись?
Написал обработчик, который обновляет записи в БД по указанным полям и значениям:
class OperationDB():
def __init__(self, DB):
self.db = DB
class MyTable_api(OperationDB):
def __init__(self, db, dbMyTable ):
super().__init__(DB=db)
self.dbMyTable = dbMyTable
def update_table(self, idRows, field_lst, data_list):
print('Пытаемся обновить таблицу в БД')
print('idRows=', idRows)
cash = self.db.session.query(self.dbMyTable).filter_by(id=int(idRows)).first()
print('cash=', cash)
if cash is None:
print('Нет такой строки!')
for ind, data in enumerate(field_lst):
print(cash.__dict__[data], '-->', data_list[ind])
cash.__dict__[data] = data_list[ind]
self.db.session.commit()
self.db.session.close()
print('Обновление таблицы успешно!')
print('Закрываем сессию!')
выдает:
Пытаемся обновить таблицу в БД
idRows= 2
cash = ....
.... --> ....
.... --> ....
.... --> ....
Обновление таблицы успешно!
Закрываем сессию!
Как видно по выводу, что все успешно отработало("..." - там данные, просто убрал, чтобы глаза не мозолило) - нигде ничего не встало.
Вопрос только в том, почему при проверке данных - они не изменились, а остались старые?
Дополнение:
- Библиотека и СУБД: SQLAlchemy, MySQL
- Если прописывать вручную, то работает:
cash = obj_MyTable_api.db.session.query(obj_MyTable_api.dbMyTable).filter_by(id=idRows).first()
print('Пытаемся обновить таблицу в БД')
print('cash=', cash)
if cash is None:
print('Нет такой строки!')
else:
cash.field1 = data_field1
cash.field2 = data_field1
cash.field3 = data_field1
cash.field4 = data_field1
cash.field5 = data_field1
cash.field6 = data_field1
obj_MyTable_api.db.session.commit()
print('Обновление таблицы успешно!')
obj_MyTable_api.db.session.close()
Ответы (2 шт):
Изменение __dict__ не влияет на изменение объекта при коммите. Скорее всего, причина в внутренней кухне, мб у объекта есть список измененных полей и они хранятся отдельно и при коммите к ним идет обращение, а если менять объект через внутренний словарь __dict__, то свойства не отмечаются как измененные, я так думаю.
Решением будет использовать setattr:
setattr(cash, data, data_list[ind])
Вообще, я бы цикл переписал:
for name, value in zip(field_lst, data_list):
setattr(cash, name, value)
PS.
Для проверки теории с __dict__ и setattr сделал такой тест:
from sqlalchemy import Column, Integer, String, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
Base = declarative_base()
class Foo(Base):
__tablename__ = 'Foo'
id = Column(Integer, primary_key=True)
name = Column(String)
value = Column(String)
value2 = Column(String)
def __str__(self) -> str:
return f'{self.id}, {self.name}, {self.value}, {self.value2}'
engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
foo = Foo(
name="Variant",
value="<ALL>",
value2="<ANY>",
)
session.add(foo)
session.commit()
print('Foo:', foo)
print()
cash = session.query(Foo).filter_by(id=int(1)).first()
print(cash)
cash.__dict__['value2'] = '!!!'
print(cash.__dict__)
session.commit()
cash = session.query(Foo).filter_by(id=int(1)).first()
print('Change __dict__:', cash)
print()
setattr(cash, 'value2', '!!!')
print(cash.__dict__)
session.commit()
cash = session.query(Foo).filter_by(id=int(1)).first()
print('Change setattr:', cash)
session.close()
Вывод:
Foo: 1, Variant, <ALL>, <ANY>
1, Variant, <ALL>, <ANY>
{'_sa_instance_state': <sqlalchemy.orm.state.InstanceState object at 0x000001F45AA55060>, 'value2': '!!!', 'name': 'Variant', 'id': 1, 'value': '<ALL>'}
Change __dict__: 1, Variant, <ALL>, <ANY>
{'_sa_instance_state': <sqlalchemy.orm.state.InstanceState object at 0x000001F45AA55060>, 'value2': '!!!', 'value': '<ALL>', 'id': 1, 'name': 'Variant'}
Change setattr: 1, Variant, <ALL>, !!!
Как видно по выводу, значение поля объекта не поменялось при __dict__, но поменялось при setattr (кст, как и сам __dict__)
Мне кажется вот так должно работать при помощи update, но нужно проверять:
for ind, data in enumerate(field_lst):
print(cash.__dict__[data], '-->', data_list[ind])
cash.update({data: data_list[ind]})