I'm a little lost interpreting Django's explanation of applying a default value to a PostgreSQL JSONField:
If you give the field a default, ensure it’s a callable such as
dict
(for an empty default) or a callable that returns adict
(such as a function). Incorrectly usingdefault={}
creates a mutable default that is shared between all instances of JSONField.
So in my model file I've declared the default as such
foo = JSONField(default=dict())
however when I generate the migration operation for the new field this is the result
migrations.AddField(
model_name='bar',
name='foo',
field=django.contrib.postgres.fields.jsonb.JSONField(default={}))
I'm just not sure whether or not this result is in accordance with the documentation's suggestion. Is this valid, or should I modify the generated default to call dict()
?
A callable is an object x
that can be called, hence x()
is valid, and will not raise an error because it is not callable (although there can be errors during the call, for example because the function somewhere yields an error).
dict()
is actually completely equivalent to {}
, that is not a callable, since {}()
, will not result in constructing anything. But dict
itself on the other hand is a reference to the dict
class, and if we call it, we construct a new dict
. So we should write it like:
# no brackets! We do not make a call, but pass the callable
foo = JSONField(default=dict)
So we do not call the dict
class, we pass a reference to the class, and such classes are callable: if you call them, you typically construct a new instance (although this behavior can be changed).
Passing the callable is of vital importance here, since otherwise Django will each time use a reference to the same dictionary. As a result changes to one of the dictionaries will change the others that change the reference. If you store the dictionary and reload it, then this will be a different dictionary, but as long as you constructed two models, during the same Python run, these would be the same objects.
If you however pass a function, the function will be called, and thus produce two different objects, both empty dictionaries. But changes to the first dictionary will not reflect in the second one.
The same holds if you for instance would want to initialize a JSON field with a dictionary that contains data, instead of writing , one has to define it like:default={'a': 4}
def default_somemodel_dict():
return {'a': 4}
class SomeModel(models.Model):
foo = JSONField(default=default_somemodel_dict)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With