对JSON字段的更新不会持久保存到DB

Tro*_*nic 14 python postgresql json sqlalchemy flask-sqlalchemy

我们有一个带有JSON字段的模型,用户标志插入其中.插入确实按预期工作,但是当删除某些标志时,它们会保留在字段中,并且更改不会持久保存到数据库.

我们的模型中有以下方法:

def del_flag(self, key):
    if self.user_flags is None or not key in self.user_flags:
        return False
    else:
        del self.user_flags[key]
        db.session.commit()        
        return True
Run Code Online (Sandbox Code Playgroud)

数据库是postgres,我们使用SQLalchemy JSON字段方言作为字段类型.有什么建议吗?

Jos*_*rón 33

如果您使用的是Postgres <9.4,则无法直接更新JSON字段.您需要使用flag_modified函数将更改报告给SQLAlchemy:

from sqlalchemy.orm.attributes import flag_modified
model.data['key'] = 'New value'
flag_modified(model, "data")
session.add(model)
session.commit()
Run Code Online (Sandbox Code Playgroud)

  • 我正在使用Postgres 10.3和SQLAlchemy 1.2.8,其列看起来像`data = Column(MutableDict.as_mutable(JSON))`,但我仍然必须这样做才能使更新工作。 (2认同)
  • 谢谢@josé-vte-calderón。我花了很长时间才发现 SQLAlchemy 没有注册对 JSON 字段所做的更改。谢谢! (2认同)
  • 除非模型对象是新的,否则不需要将其添加到数据库中。如果我们正在修改现有对象,那么 session.commit() 将保存更改。 (2认同)

how*_*ese 9

我的问题是在创建新行时引用从SQLAlchemy返回的行对象。例如,这不起作用

row = db.session.query(SomeTable).filter_by(id=someId).first()
print(row.details)
newDetails = row.details
newDetails['key'] = 'new data'
row.details = newDetails
db.session.commit()
Run Code Online (Sandbox Code Playgroud)

但是创建一个新的字典确实可以工作

row = db.session.query(SomeTable).filter_by(id=someId).first()
print(row.details)
newDetails = dict(row.details)
newDetails['key'] = 'new data'
row.details = newDetails
db.session.commit()
Run Code Online (Sandbox Code Playgroud)

注意 dict(row.details)

  • @YakovlevDenis你可能也可以`json.loads(json.dumps(dict(row.details)))`,但我还没有测试过。 (2认同)

小智 6

我正在使用JSON字段,并在下面提到了文档。

https://docs.sqlalchemy.org/zh/13/core/type_basics.html?highlight=json#sqlalchemy.types.JSON

它显示了如何使JSON-dict字段可变。(默认是不可变的)

像这样..

from sqlalchemy.ext.mutable import MutableDict
from sqlalchemy import Column, Integer, JSON

class TableABC(Base):
    __tablename__ = 'table_abc'
    id = Column(Integer, primary_key=True)
    info = Column(MutableDict.as_mutable(JSON))

Run Code Online (Sandbox Code Playgroud)

然后我可以将json字段更新为ORM。

  • SQLAlchemy==1.1.18 和 PostgreSQL 9.6 使用“JSONB”类型按预期工作 (2认同)
  • 嗨@humbledude。这个方法对我来说不起作用,使用 sqlalchemy 版本 1.3.6。我建议像其他人建议的那样使用 flag_modified 解决方案。效果很好 (2认同)