JSON 字段的更新不会持续到数据库

Posted

技术标签:

【中文标题】JSON 字段的更新不会持续到数据库【英文标题】:Updates to JSON field don't persist to DB 【发布时间】:2017-07-22 09:58:41 【问题描述】:

我们有一个带有 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

数据库是 postgres,我们使用 SQLalchemy JSON 字段方言作为字段类型。对此有何建议?

【问题讨论】:

***.com/questions/29830229/… 您需要使用mutation tracking。 【参考方案1】:

如果您使用的是 Postgres flag_modified 函数将更改报告给 SQLAlchemy:

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

【讨论】:

我正在使用 Postgres 10.3 和 SQLAlchemy 1.2.8 以及一个看起来像 data = Column(MutableDict.as_mutable(JSON)) 的列,我仍然必须这样做才能进行更新。 谢谢@josé-vte-calderón。我花了很长时间才发现 SQLAlchemy 没有注册对 JSON 字段所做的更改。谢谢! 不往下拉太多的朋友请看@humbledude的最新回复【参考方案2】:

我使用的是 JSON 字段,我参考了下面的文档。

https://docs.sqlalchemy.org/en/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))

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

【讨论】:

SQLAlchemy==1.1.18 和 PostgreSQL 9.6 使用 JSONB 类型按预期工作 嗨@humbledude。这种方法对我不起作用,使用 sqlalchemy 1.3.6 版。我会像其他人建议的那样推荐使用 flag_modified 的解决方案。效果很好 嗨@Skulas。此代码似乎根据数据库的版本起作用。我正在使用 Postgresql(Enterprise) 10.1.5 和 mysql 5.7.17。我在 SQLAlchemy 官方文档上找不到版本限制信息。【参考方案3】:

我的问题是在创建新行时引用从 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()

但是创建一个新的字典确实有效

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()

通知dict(row.details)

【讨论】:

另外,如果你想改变它们,你必须将所有嵌套节点转换为 dict。 @YakovlevDenis 你也可以json.loads(json.dumps(dict(row.details))),但我还没有测试过。 @howMuchCheeseIsTooMuchCheese 尝试了json 方法,它对我有用。

以上是关于JSON 字段的更新不会持续到数据库的主要内容,如果未能解决你的问题,请参考以下文章

EBeans 更新不保存更改的字段项

使用elasticdump实现es数据导入导出示例(持续更新中)

ThinkPHP5实用的数据库操作方法持续更新

功能测试经验汇总(--持续更新)

Json列表数据查找更新

将 $scope 更新为特定字段 json ionic backand 导致对象中的空白数据 && 验证用户名密码到来自 backand 的字段