Фильтр Django JSONField список dicts
Я запускаю Django 1.9 с новым JSONField и имею следующую тестовую модель:
class Test(TimeStampedModel):
actions = JSONField()
Скажем, действие JSONField выглядит так:
[
{
"fixed_key_1": "foo1",
"fixed_key_2": {
"random_key_1": "bar1",
"random_key_2": "bar2",
}
},
{
"fixed_key_1": "foo2",
"fixed_key_2": {
"random_key_3": "bar2",
"random_key_4": "bar3",
}
}
]
Я хочу иметь возможность фильтровать ключи foo1 и foo2 для каждого элемента списка.
Когда я это сделаю:
>>> Test.objects.filter(actions__1__fixed_key_1="foo2")
Тест находится в запросе. Но когда я это делаю:
>>> Test.objects.filter(actions__0__fixed_key_1="foo2")
Это не так, что имеет смысл. Я хочу сделать что-то вроде:
>>> Test.objects.filter(actions__values__fixed_key_1="foo2")
или
>>> Test.objects.filter(actions__values__fixed_key_2__values__contains="bar3")
И проверите тест в наборе запросов.
Любая идея, если это можно сделать и как?
Ответы
Ответ 1
Если вы не хотите фильтровать свои данные одним из полей в вашем массиве dicts, вы можете попробовать этот запрос:
Test.objects.filter(actions__contains=[{'fixed_key_1': 'foo2'}])
Он отобразит все объекты Test
, у которых есть хотя бы один объект в поле actions
, который содержит ключ fixed_key_1
значения foo2
.
Также он должен работать для вложенного поиска, даже если вы не знаете фактических индексов:
Test(actions=[
{'fixed_key_1': 'foo4', 'fixed_key_3': [
{'key1': 'foo2'},
]}
}).save()
Test.objects.filter(actions__contains=[{'fixed_key_3': [{'key1': 'foo2'}]}])
Простыми словами, contains будет игнорировать все остальное.
К сожалению, если вложенный элемент является объектом, вы должны знать имя ключа. В этом случае поиск по значению не будет работать.
Ответ 2
Вы можете использовать пакет django-jsonfield, я думаю, это уже тот, который вы используете.
from jsonfield import JSONField
class Test(TimeStampedModel):
actions = JSONField()
Итак, чтобы выполнить поиск по определенному свойству, вы можете просто сделать это:
def test_filter(**kwargs):
result = Test.objects.filter(actions__contains=kwargs)
return result
Если вы используете PostgreSQL, возможно, вы можете использовать PostgreSQL конкретные поля модели.
PS: Если вы имеете дело с большим количеством структуры JSON, возможно, вам стоит рассмотреть возможность использования базы данных NoSQL.
Ответ 3
Вы должны иметь возможность использовать поиск __contains
для этого и передавать запрашиваемые значения в виде списка, как __contains
здесь. Поиск будет вести себя точно так же, как ArrayField. Итак, что-то вроде этого должно работать:
Test.objects.filter(actions__contains=[{'fixed_key_1': 'foo2'}])