Home  >  Article  >  Backend Development  >  How to update the values ​​of multiple keys in a JsonField using the .update() method using Django's ORM?

How to update the values ​​of multiple keys in a JsonField using the .update() method using Django's ORM?

WBOY
WBOYforward
2024-02-06 09:48:12977browse

如何使用 Django 的 ORM 使用 .update() 方法更新 JsonField 中多个键的值?

Question content

I have a model field that I'm trying to update using django's .update() method. The field is a jsonfield. I usually keep a dictionary in this area. For example{"test": "Yes", "prod": "No"}

This is the model:

class question(models.model):
    # {"test": "yes", "prod": "no"}
    extra_data = models.jsonfield(default=dict, null=true, blank=true)

I can update the keys within the dictionary using this query (which works great, btw):

Question.filter(id="123").update(meta_data=Func(
                        F("extra_data"),
                        Value(["test"]),
                        Value("no", JSONField()),
                        function="jsonb_set",
                    ))

Now the question is, is there a way to update multiple keys (in my case two) at once using .update() as shown in the above query?

I want to achieve this using the .update() method instead of .save() so that I can avoid calling the post_save signal function.


Correct Answer


Disclaimer: It will look ugly.

I've done this in the past, albeit using pure sql, not django. The idea is to call jsonb_set() recursively. Each call sets a key.

So, in sql, to set the key {"test":"yes","prod":"no"} You can do this:

update question set meta_data = jsonb_set(jsonb_set(extra_data, '{test}', '"yes"'::jsonb), '{prod}', '"no"'::jsonb)
where id = 123;

Please note that jsonb_set has two nested calls, the innermost one uses meta_data, and the outermost one receives the innermost result.

So the django equivalent would look like this (note, untested):

question.filter(id="123").update(
    meta_data=func(
        func(
            f("extra_data"),
            value(["test"]),
            value("yes", jsonfield()),
            function="jsonb_set",
        ),
        value(["prod"]),
        value("no", jsonfield()),
        function="jsonb_set",
    ))

Or you can create a recursive function that returns the mess for you, setting one item at a time:

def recursive_jsonb_set(original, **kwargs):
    if kwargs:
        key, value = kwargs.popitem()
        return Func(
            recursive_jsonb_set(original, **kwargs),
            Value(key.split('__')),
            Value(value, JSONField()),
            function="jsonb_set")
    else:
        return original

Question.filter(id="123").update(
    meta_data=recursive_jsonb_set(F("extra_data"), test="yes", prod="no", other__status="done"))

Please note the '__' function to update subkeys.

The above is the detailed content of How to update the values ​​of multiple keys in a JsonField using the .update() method using Django's ORM?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:stackoverflow.com. If there is any infringement, please contact admin@php.cn delete