这是一个非常复杂的问题,所以让我解释一下。我有一个名为 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 个查询集(一个年龄不为空,一个为空)尝试了联合方法,并使用|
运算符将它们连接起来。这不起作用,因为订购搞砸了。我还尝试了在另一个问题中发现的这种奇怪的方法(也没有用):
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。