I've recently updated to Django 1.9 and tried updating some of my model fields to use the built-in JSONField (I'm using PostgreSQL 9.4.5). As I was trying to create and update my object's fields, I came across something peculiar. Here is my model:
class Activity(models.Model):
activity_id = models.CharField(max_length=MAX_URL_LENGTH, db_index=True, unique=True)
my_data = JSONField(default=dict())
Here is an example of what I was doing:
>>> 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'
It seems whenever I update any field in my_data
, the next object I create pre-populates itself with the data from my_data
from the previous object. This happens whether I use get_or_create
or just create
. Can someone explain to me what is happening?
The problem is that you are using default=dict()
. Python dictionaries are mutable. The default dictionary is created once when the models file is loaded. After that, any changes to instance.my_data
alter the same instance, if they are using the default value.
The solution is to use the callable dict
as the default instead of dict()
.
class Activity(models.Model):
my_data = JSONField(default=dict)
The JSONField docs warn about this:
If you give the field a
default
, ensure it’s a callable such asdict
(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 ofJSONField
.
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