Django 1.9. Changing the behavior of JSONField.

I recently updated Django 1.9 and tried to update some of my model fields to use the built-in JSONField (I use PostgreSQL 9.4.5). When I tried to create and update object fields, I came across something special. 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 that whenever I update any field in my_data , the next object that I create pre-populates the data from my_data from the previous object. This happens if I use get_or_create or just create . Can someone explain to me what is going on?

+5
source share
1 answer

The problem is that you are using default=dict() . Python dictionaries are mutable. The default dictionary is created once when the model file is loaded. After that, any changes to instance.my_data change the same instance if they use the default value.

The solution is to use the called dict as the default instead of dict() .

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

JSONField docs warn about this:

If you give the field a default , make sure its called, for example, dict (for empty by default) or called, which returns a dict (for example, a function). Incorrect use of default={} creates a mutable default value that is shared between all instances of JSONField .

+17
source

Source: https://habr.com/ru/post/1243322/


All Articles