【问题标题】:SQLAlchemy JSON TypeDecorator not saving correctly, issues with session.commit()SQLAlchemy JSON TypeDecorator 没有正确保存,session.commit() 的问题
【发布时间】:2015-07-17 06:14:22
【问题描述】:

我的 models.py 文件有两个模型,用户和作业。

每个作业都有多个与之关联的用户。

一个用户可以关联多个工作。

我需要能够做类似 job.getUsers() --> 用户对象列表

我尝试使用 TypeDecorators 在我的 Job 表中存储一个 JSON int 数组。每个 int 代表一个用户的 pk,我以后可以使用它在 db 中找到正确的行。

乍一看,这工作正常,但我遇到了一些奇怪的错误(帖子底部,在我的代码之后)。

class Json(TypeDecorator):

    impl = String

    def process_bind_param(self, value, dialect):
        return json.dumps(value)

    def process_result_value(self, value, dialect):
        return json.loads(value)


class Job(Base):
    __tablename__ = 'jobs'
    id = Column(Integer, primary_key=True)
    date = Column(Date)
    workers = Column(Json(128))

    def __init__(self):
        self.workers = []

这是我奇怪的输出

>>> db_session = scoped_session(sessionmaker(autocommit=False, autoflush=True, bind=engine))

>>> job = Job()
>>> job.workers
[]
>>> job.workers.append(1)
>>> job.workers
[1]
>>> db_session.add(job)
>>> job.workers
[1]
>>> db_session.commit()
>>> job.workers
[1]
>>> job = Job.query.filter(Job.id == 1).first()
>>> job.workers
[1]

此时,看起来一切正常。当我尝试向列表中添加第二个项目时,事情开始出错。

>>> job.workers.append(2) # let's try adding another item to the list.
>>> job.workers
[1, 2]
>>> db_session.add(job) # is this necessary? added for debugging purposes, seems to have no effect on anything
>>> job.workers
[1, 2]
>>> db_session.commit() # autoflush is on
>>> job.workers
[1] # !!!!!!!!!!!!!!!!!!!??????????????????????/

如果您知道我做错了什么,请告诉我。或者,让我知道是否有更好的方法来代替 JSON TypeDecorator。谢谢!

【问题讨论】:

标签: python json sqlalchemy


【解决方案1】:

SQLAlchemy 在持久保存已更新的 JSON 时存在问题。我遇到了同样令人沮丧的问题,但在这里找到了答案:

https://bashelton.com/2014/03/updating-postgresql-json-fields-via-sqlalchemy/

总之,使用 sqlalchemy.orm.attributes 中的 'flag_modified' 方法

from sqlalchemy.orm.attributes import flag_modified    

jobs.workers.append(2)
flag_modified(jobs, "workers")
db_session.commit()

【讨论】:

  • 感谢您回答艾伦,您可以从链接参考中添加答案摘要吗?它可以帮助您的答案在链接中断的情况下仍然有用。
  • 如果您需要在 Python 中处理嵌套字典和列表,请参阅这个 MutableDict 配方variable-scope.com/posts/…
  • @MikkoOhtamaa 您的链接已损坏。最好在答案中发布信息
【解决方案2】:

我刚刚遇到了同样的问题,如果json文件在python中具有相同的id,似乎SQLAlchemy的更新将不会被执行。

所以我的解决方案是为 json 文件分配一个新对象。下面的代码应该可以工作:

job.workers = job.workers + [2, ]
db_session.add(job)
db_session.save()

【讨论】:

    【解决方案3】:

    在我的应用中,我首先通过复制数据来解决这个问题:

    import copy
    
    workers = copy.deepcopy(job.workers)
    workers.append(2)
    job.workers = workers
    

    我使用了deepcopy,因为我的数据是一个更复杂的对象。

    【讨论】:

    • 我尝试了deepcopy,但没有成功。即使在.add(<var>) 操作之后也可以看到嵌套数据,但在.commit() 之后不能看到
    【解决方案4】:

    这对我有帮助。

    from flask import Flask
    from flask_sqlalchemy import SQLAlchemy
    from sqlalchemy.ext.mutable import MutableDict # <--- !
    
    app = Flask(__name__)
    db = SQLAlchemy(app)
    
    class SomeModel(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    data = db.Column(MutableDict.as_mutable(db.JSON)) # <--- !
    

    【讨论】:

      猜你喜欢
      • 2019-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-17
      • 1970-01-01
      • 1970-01-01
      • 2021-12-21
      • 1970-01-01
      相关资源
      最近更新 更多