12

I currently became familiar with using JSONField in django rest-framework, but I could not find any straight forward way to update a key in a stored json. There are many ways to filter JSONField depends on its internal keys, but it seems that there is no way to change, update or delete a key from already stored JSONField. But it seems that postgres can do some modifications on json keys as this answer explained.

Is there any function which is able to do modifications on JSONFields. If there is not any direct command to do this, what is the best way to implement modifications of a JSONField?

Edit:

As an example if I have a model like this:

class Thing(models.Model):
    name = models.CharField()
    properties = JSONField()

And in properties I stored a json like this :

{
"color" : "red",
"size" : "large",
"cost" : 1234
}

Then I want to change the color to "green" by using django commands.

Community
  • 1
  • 1
motam
  • 677
  • 1
  • 6
  • 24
  • Can you give an example of what sort of an update you are looking for. The easiest way is to read it into python, modify as a dictionary, and save. – serg Apr 17 '16 at 21:36
  • @serg please see the edit note. – motam Apr 18 '16 at 04:07

5 Answers5

16
thing = Thing.objects.get(name="...")
thing.properties['color'] = 'green'
thing.save()
serg
  • 109,619
  • 77
  • 317
  • 330
  • Sorry I could not check your answer now, But I will check this as soon as possible and get you a feedback. – motam Apr 18 '16 at 06:10
  • @serg I checked your answer, I think `properties` in `thing` is not something like dictionary or json (it is a `unicode`) so you need some middle operations to change it to a dictionary then again save it. It seems that django does not support this so I have to do something like you write here. – motam Apr 18 '16 at 17:07
  • It is supposed to be a dictionary, are you using the latest Django, and Postgres db 9.4+? What is the value of the properties field, json as a string(unicode)? Also if you can go to the postgres console and check that your properties field type is `jsonb`. – serg Apr 18 '16 at 17:19
  • Sorry for my late answer, you are right in current version it is a dictionary, although yet in some situations it is not a dictionary that seems strange to me, but in most cases is a dictionary. – motam Apr 29 '16 at 18:26
  • 3
    is there a way to do it with `.update()`? – StriveForBest Apr 07 '21 at 19:02
  • @StriveForBest Check my answer. – Vladius001 Apr 08 '21 at 14:39
  • General reference: `{"a": 1}` is valid JSON. If stored in a `JSONField`, it would be returned as a dictionary. However, `"some string"`, `[1, 2, 3, 4]` and `true` are also valid JSON documents, which obviously would not be returned as dictionaries. – tzot Oct 12 '21 at 16:28
16

The approach with jsonb_set from @tarasinf and @Vladius001 does also work with Django's Func expression.

from django.db.models import F, Func, Value, JSONField

Thing.objects.update(
    properties=Func(
        F("properties"),
        Value(["color"]),
        Value("green", JSONField()),
        function="jsonb_set",
    )
)
radtek
  • 34,210
  • 11
  • 144
  • 111
foonicorn
  • 161
  • 1
  • 2
1

For your model:

class Thing(models.Model):
    name = models.CharField()
    properties = JSONField()

If you need to update bunch of entries, you can do the following:

Thing.objects.update(
    properties=RawSQL("jsonb_set(properties, '{color}', 'green', true)", [])
)

color: green will be inserted, if not exists.

Welcome to PostgreSQL docs for more information about jsonb_set.

Vladius001
  • 720
  • 1
  • 6
  • 11
0

The next syntax works for me,

  • Django==2.2.19
  • Postgres==12.0.6
from django.db.models.expressions import RawSQL
Thing.objects.update(properties=RawSQL("""jsonb_set(properties, \'{"name"}\',\'"name value"\', true)""", []))
tarasinf
  • 796
  • 5
  • 17
-3

You can find better solution here https://django-postgres-extensions.readthedocs.io/en/latest/json.html