Django 1.9 JSONField update behavior

2024/10/15 16:24:31

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?

Answer

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 as dict (for an empty default) or a callable that returns a dict (such as a function). Incorrectly using default={} creates a mutable default that is shared between all instances of JSONField.

https://en.xdnf.cn/q/69263.html

Related Q&A

Using Tweepy to search for tweets with API 1.1

Ive been trying to get tweepy to search for a sring without success for the past 3 hours. I keep getting replied it should use api 1.1. I thought that was implemented... because I can post with tweepy.…

Retrieving my own data via FaceBook API

I am building a website for a comedy group which uses Facebook as one of their marketing platforms; one of the requirements for the new site is to display all of their Facebook events on a calendar.Cur…

Python -- Optimize system of inequalities

I am working on a program in Python in which a small part involves optimizing a system of equations / inequalities. Ideally, I would have wanted to do as can be done in Modelica, write out the equation…

Pandas side-by-side stacked bar plot

I want to create a stacked bar plot of the titanic dataset. The plot needs to group by "Pclass", "Sex" and "Survived". I have managed to do this with a lot of tedious nump…

Turn off list reflection in Numba

Im trying to accelerate my code using Numba. One of the arguments Im passing into the function is a mutable list of lists. When I try changing one of the sublists, I get this error: Failed in nopython …

Identifying large bodies of text via BeautifulSoup or other python based extractors

Given some random news article, I want to write a web crawler to find the largest body of text present, and extract it. The intention is to extract the physical news article on the page. The original p…

Pandas reindex and interpolate time series efficiently (reindex drops data)

Suppose I wish to re-index, with linear interpolation, a time series to a pre-defined index, where none of the index values are shared between old and new index. For example# index is all precise times…

How do you set the box width in a plotly box in python?

I currently have the following;y = time_h time_box = Box(y=y,name=Time (hours),boxmean=True,marker=Marker(color=green),boxpoints=all,jitter=0.5,pointpos=-2.0 ) layout = Layout(title=Time Box, ) fig = F…

how do you install django older version using easy_install?

I just broke my environment because of django 1.3. None of my sites are able to run. So, i decided to use virtualenv to set virtual environment with different python version as well as django.But, seem…

Whats difference between findall() and iterfind() of xml.etree.ElementTree

I write a program using just like belowfrom xml.etree.ElementTree import ETxmlroot = ET.fromstring([my xml content])for element in xmlroot.iterfind(".//mytag"):do some thingit works fine on m…