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

WBOY
Release: 2024-02-06 09:48:12
forward
912 people have browsed it

如何使用 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)
Copy after login

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",
                    ))
Copy after login

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;
Copy after login

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",
    ))
Copy after login

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"))
Copy after login

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!

source:stackoverflow.com
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!