Фильтрация элементов Django JSONB в списке

#django #postgresql #jsonb

#django #postgresql #jsonb

Вопрос:

У меня есть Django data JSONField со следующими данными в

 {
    "title": "Some Title",
    "projects": [
        {"name": "Project 1", "score": "5"},
        {"name": "Project 2", "score": "10"},
        {"name": "Project 3", "score": "2"},
    ]
}
 

И мне нужно фильтровать строки по оценкам проекта (числовой тип), т.е. where project -> score <= 5

Django ORM предоставляет основы фильтрации и работы с полем Postgres JSONB. То есть я могу сделать

 Model.objects.filter(data__title="Some Title")
 

Но это не так просто при наличии списка элементов в столбце JSON, т. Е. Я не могу сделать

 Model.objects.filter(data__projects__score__lte=5)

Only way I can reach the `score` in Django ORM is to use the array index, i.e.

Model.objects.filter(data__projects__0__score__lte=5)
 

Но сейчас это не работает, меня интересуют все элементы в этом списке, которых может быть сколько угодно

Где я сейчас нахожусь:

Я присоединил этот список к набору запросов как jsonb_array_elements

 queryset.query.join(join=join_cfg)
 

Который добавил следующий sql к ЗАПРОСУ

 LEFT JOIN LATERAL jsonb_array_elements("my_table"."data" -> 'projects') projects ON TRUE
 

Теперь, в необработанном SQL, я могу сделать что-то вроде этого, чтобы отфильтровать этот список

 WHERE (projects->>'score')::numeric < 5
 

Проблема в том, что я не могу заставить это хорошо работать с Django ORM

В настоящее время я добавляю это WHERE предложение, используя queryset.extra()

 queryset = queryset.extra(where=where_clause)
 

Проблема с этим заключается в том, что при использовании .extra() предложение WHERE редактируется AND в конце запроса, что приводит к неожиданным результатам в сочетании с другими фильтрами, выполняемыми с использованием Q объектов Django.

Т.е. Последнее сгенерированное предложение WHERE выглядит следующим образом:

 WHERE condition1 AND (condition2 OR condition3) AND MY_CUSTOM_WHERE_CONDITION

// but what I need is 

WHERE condition1 AND (condition2 OR condition3 OR MY_CUSTOM_WHERE_CONDITION)
 

В идеале это пользовательское условие должно быть добавлено вместе с Q объектом, т.е.

 query_filters |= Q(projects__score__lte=5)
 

Но поскольку projects столбец является пользовательским соединением, я понимаю Cannot resolve keyword 'projects' into field. , что не могу использовать django ORM для фильтрации так же, как я фильтрую title в начале этого сообщения


Я думаю, что это пользовательское соединение должно быть каким-то образом аннотировано, а затем использовать Q объект в этом аннотированном столбце, но я не могу заставить это работать.

Я пробовал, дополнительный выбор, аннотации с помощью RawSql, FilteredRelation, все..

Любая помощь приветствуется. Спасибо