Django 1.9 JSONField更新行为

时间:2016-02-18 13:51:30

标签: python json django postgresql

我最近更新到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,都会发生这种情况。有人可以向我解释发生了什么吗?

2 个答案:

答案 0 :(得分:19)

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

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

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

JSONField docs对此发出警告:

  

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

答案 1 :(得分:0)

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