Это очень сложный вопрос, поэтому позвольте мне объяснить.У меня есть модель с именем Person, которая хранит большую часть своих данных в JSONField.
class Person(models.Model):
data = JSONField()
Теперь поле данных обычно имеет следующий формат:
{"name" : <String>, "age" : <int>}
Теперь, чтоЯ хочу сделать, это создать набор запросов Person, который упорядочивает объекты, используя атрибут age
из своего поля data
, в порядке убывания.Это решается с помощью следующего кода:
from django.db.models.expressions import RawSQL
from .models import Person
qs = Person.objects.annotate(age=RawSQL("(data->>'age')::int", [])).order_by('-age')
Это замечательно и хорошо работает.Однако во время тестирования я изменил атрибут data
одного объекта Person на что-то вроде этого:
{"name" : <String>, "profession" : <String>}
То есть этот объект не имеет атрибута age
в своем поле data
,Теперь, когда я выполняю запрос выше, он все еще работает нормально, но этот объект (объект без атрибута age
) находится на самом верху.Это из-за одной из двух причин:
- Поскольку его
age
равен нулю, он отправляется наверх из-за убывающей функции order_by. - Это объект, который я создал в последний разТаким образом, это всегда было в начале, но поскольку он не имеет атрибута
age
, на него просто не влияет функция order_by, и он остается в исходном положении.
На самом деле я хочу отправить все объекты, которые не имеют атрибута age
в их поле data
, в самый конец набора запросов.
Я попробовал метод объединениясоздав 2 набора запросов (один, где age не равен null, а другой - где он есть), и объединил их, используя оператор |
.Это не сработало, потому что порядок был испорчен.Я также попробовал этот странный метод, который я нашел в другом вопросе (который также не работал):
qs = Person.objects.annotate(age=RawSQL("(data->>'age')::int", [])).extra(select={'is_top': "age__isnull=True"})
qs = qs.extra(order_by('-is_top')
Ссылка на странное решение, которое не работало
В любом случаеЕсть ли способ сделать это, который не включает списки, itertools и цепочки?Потому что я слышал, что иногда они могут быть довольно медленными.
Спасибо!
Примечание: Пожалуйста, не отвечайте о нормализации базы данных для этих запросов вместо использования JSONFields.Я хорошо осведомлен о преимуществах нормализации, но для моего случая использования это должен быть JSONField.