1

I have a class with a json field in it

class A(models.Model)
    brand = JSONField()

If I post an array of JSON like [{'brand_id:1', 'name':'b1'}, {'brand_id:2', 'name':'b2'}] it is stored as an array of JSON. This works fine.

How should I query so as to check if '1' is present in the brand_id of any dictionary in that array?

1

2 Answers 2

5

Well first of all your JSON here is malformed. I presume it is meant to be:

[{'brand_id': 1, 'name': 'b1'}, {'brand_id': 2, 'name': 'b2'}] 

If that's the case, to test for 1 in such a blob, something like this will tell you if 1 is to be found anywhere in the JSON as a value:

def check_for_one(json_data):
    return any([1 in data.values() for data in json_data])

But you want to know specifically if 1 is a value owned by a key brand_id anywhere in the JSON so you can also use a loop to add in some extra conditions:

def check_for_one(json_data):
    match = []
    for data in json_data:
        for key, value in data.items():
            if key == 'brand_id' and value == 1:
                match.append(True)
    return any(match)

You can incorporate such logic as methods on your model class like this:

class A(models.Model):
    brand = JSONField()

    def check_for_one_comprehension(self):
        return any([1 in data.values() for data in self.brand])

    def check_for_one_loop(self):
        match = []
        for data in self.brand:
            for key, value in data.items():
                if key == 'brand_id' and value == 1:
                    match.append(True)
        return any(match)

But, if you actually want to filter instances from the database where the JSON data is an array at the top level and brand_id == 1, that needs a different approach, and this should do it:

A.objects.filter(brand__contains=[{'brand_id': 1}])

Note the additional [{}] braces! If you just call contains=['brand_id': 1] it will throw a syntax error and if you call contains={'brand_id': 1} it will not match.

Sign up to request clarification or add additional context in comments.

3 Comments

Can you explain why brand__contains=[{'brand_id': 1}] works but brand__contains={'brand_id': 1} does not?
Because contains={'brand_id': 1} is not taking account of the fact it needs to filter through the top-level list we have with the json shaped like: brand = [{'brand_id': 1, 'name': 'b1'}, {'brand_id': 2, 'name': 'b2'}] . If the json was shaped like brand = {'brand_id': 1, 'name': 'b1'}, then it would match.
Very helpful. Note that if the JSON structure is not a list (e.g., {'brand_id: 1}, no []s), then you don't need the []s in python.
2

This worked:

A.objects.filter(brands__contains=[{'brand_id':1}])

I didnt check it first by using the array. Link pointed put by @Bear Brown gives sufficient info. Its easy in django, but finding it out took time :P.

5 Comments

This does not work if the JSON Field stores an array.
@rtindru not true, you can filter through a json array but you would need the {} in this case to cast the key and value correctly. ['brand_id':1] will throw a syntax error.
@jhrr True; the code above raises a SyntaxError. Can you describe how the filter would work inside the JSON field if the field stores a JSON array?
@rtindru I have put the correct version in my main answer above. See the very end of that.
Works like a charm; my mistake. I was missing the array notation. Can you explain why brand__contains=[{'brand_id': 1}] works but brand__contains={'brand_id': 1} does not?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.