我正在使用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'],并打印返回
True, True
继续从上面的[编辑]继续下一个请求(上面已经提交)
def view(request):
mylst = DBSession.query(MyList).get(1)
mylst.lst.append('65')
print(DBSession.is_active, DBSession.is_modified(mylst))
数据库不会更新,它仍然是[' 45']并打印返回
True, False
我做错了什么或这是一个错误?
答案 0 :(得分:10)
默认情况下,SQLAlchemy只跟踪值本身的更改,这对于简单值(如int和字符串)“按预期”工作:
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文档中的Mutation Tracking章节,了解如何对列表或字典进行子类化,以便跟踪元素的修改。
另外,既然你提到你正在使用Postgres - 在Postgres中有一个专用的ARRAY
类型,如果您只需要存储列表,则可以使用JSON
而不是ARRAY
。但是,上面关于变异跟踪的内容也适用于{{1}}类型的列。
答案 1 :(得分:2)
您可以将实例标记为手动修改
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)
答案 2 :(得分:-2)
DBSession.flush()
后尝试mylst.lst.append('45')
。这允许您在pyramid_tm执行提交之前更新数据库。
可在此处找到更多信息:http://docs.sqlalchemy.org/en/latest/orm/session.html#flushing