在迁移文件中正确声明空Django PostgreSQL JSONField默认值

r3d*_*00d 8 python django postgresql

我有点迷失了解释Django对PostgreSQL JSONField应用默认值解释:

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

所以在我的模型文件中,我已经声明了默认值

foo = JSONField(default=dict())
Run Code Online (Sandbox Code Playgroud)

但是,当我为新字段生成迁移操作时,这就是结果

migrations.AddField(
    model_name='bar',
    name='foo',
    field=django.contrib.postgres.fields.jsonb.JSONField(default={}))
Run Code Online (Sandbox Code Playgroud)

我只是不确定这个结果是否符合文档的建议.这是有效的,还是应该修改生成的默认值来调用dict()

Wil*_*sem 17

一个可调用的对象x可以被调用,因此x()是有效的,因为它不是可调用的(因为函数某处产生错误虽然可以在通话过程中出现错误,例如)不会引发错误.

dict()实际上完全等同{},这不是可调用的,因为{}(),不会导致构造任何东西.但dict另一方面,它本身就是对dict类的引用,如果我们称之为它,我们构造一个新的 dict.所以我们应该写它:

# no brackets! We do not make a call, but pass the callable
foo = JSONField(default=dict)
Run Code Online (Sandbox Code Playgroud)

所以我们调用dict类,我们传递对类的引用,这些类是可调用的:如果你调用它们,通常构造一个新实例(尽管可以改变这种行为).

传递callable在这里至关重要,因为否则Django每次都会使用对同一个字典的引用.因此,更改其中一个词典将更改其他更改引用的词典.如果你存储字典并重新加载它,那么这将是一个不同的字典,但只要你构建了两个模型,在同一个Python运行期间,这些将是相同的对象.

但是,如果您传递一个函数,则会调用该函数,从而生成两个不同的对象,都是空字典.但是第一本字典的更改不会反映在第二本字典中.

例如,如果您想要使用包含数据的字典初始化JSON字段,而不是写入default={'a': 4},则必须将其定义为:

def default_somemodel_dict():
    return {'a': 4}

class SomeModel(models.Model):
    foo = JSONField(default=default_somemodel_dict)
Run Code Online (Sandbox Code Playgroud)

  • 很好的答案。这应该包含在 JSONField 的官方文档中 (3认同)