Я использую пирамиду с sqlalchemy, pyramid_tm и postgresql, чтобы проверить это.
DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
Base = declarative_base()
class MyList(Base):
id = Column(Integer, primary_key=True)
lst = Column(JSON)
Я использую postgresql 9.3+ и использую тип JSON. Когда я делаю это
mylst = MyList(lst=[])
Я могу видеть, что в базе данных также создается пустой [] список, а
def view(request):
mylst = DBSession.query(MyList).get(1)
mylst.lst.append('45')
print(DBSession.is_active, DBSession.is_modified(mylst))
я могу видеть ['45'] в базе данных, а print возвращает
True, True
продолжение сверху [edit] при следующем запросе (выше уже сделано)
def view(request):
mylst = DBSession.query(MyList).get(1)
mylst.lst.append('65')
print(DBSession.is_active, DBSession.is_modified(mylst))
db не будет обновляться, он все еще ['45'] и печать возвращает
True, False
Я делаю что-то неправильно или это ошибка?
По умолчанию SQLAlchemy отслеживает только изменения самого значения, которое работает "как положено" для простых значений, таких как целые и строки:
alice.name = "Alice"
alice.age = 8
Это также работает, когда вы присваиваете новое значение столбцу "сложного типа", например dict или list:
alice.toys = ['doll', 'teddy bear']
Однако SQLAlchemy не замечает изменений, если вы изменяете один из элементов в списке или добавляете/удаляете значение:
alice.toys[0] = 'teapot'
alice.toys.append('lego bricks')
Чтобы это работало, вы можете убедиться, что каждый раз вы назначаете новый список:
toys = alice.toys[:] # makes a "clone" of the existing list
toys[0] = 'teapot'
toys.append('lego bricks')
alice.toys = toys
Или прочитайте главу " Отслеживание мутаций" в документации по SQLAlchemy, чтобы увидеть, как вы можете создать подкласс для списка или указания, чтобы они могли отслеживать изменения своих элементов.
Кроме того, поскольку вы упомянули, что используете Postgres - в Postgres есть специальный тип ARRAY
который вы можете использовать вместо JSON
если все, что вам нужно, это хранить списки. Однако сказанное выше о слежении за мутациями применимо и к столбцам типа ARRAY
.
Вы можете указать экземпляр с измененным вручную
from sqlalchemy.orm.attributes import flag_modified
def view(session):
mylst = Session.query(MyList).get(1)
mylst.lst.append('45')
flag_modified(mylst, 'lst') # flag its `lst' attribute is modified
print(Session.is_active, Session.is_modified(mylst))
# (True, True)
Попробуйте DBSession.flush()
после mylst.lst.append('45')
. Это позволяет вам обновить БД до того, как pyramid_tm выполнит фиксацию.
Дополнительную информацию можно найти здесь: http://docs.sqlalchemy.org/en/latest/orm/session.html#flushing
Column(JSON)
наColumn(ARRAY)
? Кажется, я должен также указать тип. Но как мне определить массив, который может содержать словари?