Django 1.9 JSONField 更新行为

Posted

技术标签:

【中文标题】Django 1.9 JSONField 更新行为【英文标题】:Django 1.9 JSONField update behavior 【发布时间】:2016-05-30 17:27:23 【问题描述】:

我最近更新到 Django 1.9 并尝试更新我的一些模型字段以使用内置 JSONField(我使用的是 PostgreSQL 9.4.5)。当我试图创建和更新对象的字段时,我遇到了一些奇怪的东西。这是我的模型:

class Activity(models.Model):
    activity_id = models.CharField(max_length=MAX_URL_LENGTH, db_index=True, unique=True)
    my_data = JSONField(default=dict())

这是我正在做的一个例子:

>>> from proj import models
>>> test, created = models.Activity.objects.get_or_create(activity_id="foo")
>>> created
True
>>> test.my_data['id'] = "foo"
>>> test.save()
>>> test
<Activity: "id": "foo">
>>> test2, created2 = models.Activity.objects.get_or_create(activity_id="bar")
>>> created2
True
>>> test2
<Activity: "id": "foo">
>>> test2.activity_id
'bar'
>>> test.activity_id
'foo'

似乎每当我更新my_data 中的任何字段时,我创建的下一个对象都会使用来自前一个对象的my_data 的数据预先填充自己。无论我使用get_or_create 还是仅使用create,都会发生这种情况。有人可以向我解释发生了什么吗?

【问题讨论】:

【参考方案1】:
from django_postgres_extensions.models.expressions import Key
obj = Product.objectsannotate(Key('description', 'Details')).get()
obj = Product.objects.annotate(Key('description', 'Details__Rating')).get()
obj = Product.objects.annotate(Key('description', 'Tags__1')).get()

Product.objects.update(description__ = 'Industry': 'Movie', 'Popularity': 'Very Popular')

Product.objects.update(description__del ='Details')
Product.objects.update(description__del = 'Details__Release')
Product.objects.update(description__del='Tags__1')

【讨论】:

【参考方案2】:

问题是您使用的是default=dict()。 Python 字典是可变的。加载模型文件时会创建一次默认字典。之后,对instance.my_data 的任何更改都会更改同一个实例,如果它们使用默认值的话。

解决方案是使用可调用的dict 作为默认值,而不是dict()

class Activity(models.Model):
    my_data = JSONField(default=dict)

JSONField docs 对此发出警告:

如果您为该字段指定 default,请确保它是可调用的,例如 dict(对于空默认值)或返回 dict 的可调用(例如函数)。错误地使用default= 会创建一个可变的默认值,该默认值在JSONField 的所有实例之间共享。

【讨论】:

哇,我以为我已将其更改为可调用对象。感谢您指出这个简单的错误!

以上是关于Django 1.9 JSONField 更新行为的主要内容,如果未能解决你的问题,请参考以下文章

在 django rest 框架中更新 JSONField

Django / PostgresQL jsonb (JSONField) - 将选择和更新转换为一个查询

django jsonfield 保存到数据库

将 JSONField 解压缩到多个 django 表单字段中

DJango 1.9 个人资料注册+更新

我应该如何从 bradjasper 的 django-jsonfield 升级到 Django 的内置 jsonfield?