SQLAlchemy JSON TypeDecorator未正确保存,session.commit()

时间:2015-05-06 21:40:00

标签: python json sqlalchemy

我的models.py文件有两个模型,User和Job。

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

用户可以与多个职位相关联。

我需要能够做像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。谢谢!

4 个答案:

答案 0 :(得分:11)

SQLAlchemy存在持续更新JSON的问题。我有同样令人沮丧的问题,但在这里找到答案:

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

总之,使用' flag_modified' sqlalchemy.orm.attributes

中的方法
from sqlalchemy.orm.attributes import flag_modified    

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

答案 1 :(得分:1)

我遇到了同样的问题,如果json在python中提交了相同的id,那么SQLAlchemy的更新似乎不会被执行。

所以我的解决方案是为json字段分配一个新对象。下面的代码应该有效:

$articles = new Article;
$articles = $articles->orderBy('created_at', 'DESC');

$pagination = $articles->paginate(5);

foreach($pagination as $s) {
    dump($s);
}

dd($pagination);

答案 2 :(得分:1)

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

import copy

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

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

答案 3 :(得分:1)

这就是帮助我的原因。

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)) # <--- !