我有以下包含JSONField的django模型:
class RatebookDataEntry(models.Model):
data = JSONField(blank=True, default=[])
last_update = models.DateTimeField(auto_now=True)
class Meta:
verbose_name_plural = 'Ratebook data entries'
数据字段包含此json:
{
"annual_mileage": 15000,
"description": "LEON DIESEL SPORT COUPE",
"body_style": "Coupe",
"range_name": "LEON",
"co2_gkm_max": 122,
"manufacturer_name": "SEAT"
}
我可以通过其中一个数据字段对查询集进行排序吗?此查询无效。
RatebookDataEntry.objects.all().order_by("data__manufacturer_name")
答案 0 :(得分:19)
正如Julien所说,Django尚不支持JSONField
上的排序。但是可以通过RawSQL
使用PostgreSQL functions for jsonb来实现。在OP的情况下:
from django.db.models.expressions import RawSQL
RatebookDataEntry.objects.all().order_by(RawSQL("data->>%s", ("manufacturer_name",)))
答案 1 :(得分:9)
自Django 1.11起,可以使用django.contrib.postgres.fields.jsonb.KeyTextTransform
代替RawSQL
from django.contrib.postgres.fields.jsonb import KeyTextTransform
qs = RatebookEntry.objects.all()
qs = qs.annotate(manufacturer_name=KeyTextTransform('manufacturer_name', 'data'))
qs = qs.order_by('manufacturer_name')
# or...
qs = qs.order_by('-manufacturer_name')
在Django 1.10上,你必须自己继承KeyTransform
:
from django.contrib.postgres.fields.jsonb import KeyTransform
class KeyTextTransform(KeyTransform):
operator = '->>'
nested_operator = '#>>'
_output_field = TextField()
注意:KeyTransform
和KeyTextTransform
之间的区别在于KeyTransform
将返回对象的JSON表示形式,而KeyTextTransform
将返回对象的值。< / p>
例如,如果data
为{"test": "stuff"}
,KeyTextTransform
将返回'stuff'
,而KeyTransform
将返回'"stuff"'
(可以解析) json.loads
)
答案 2 :(得分:6)
通过Daniil Ryzhkov回答和Eugene Prikazchikov评论,您应该能够在JSON数据字段上对ASC和DESC进行排序,而无需使用RawSQL
和OrderBy
同时注释您的查询集。此外,您可以通过添加LOWER
:
from django.db.models.expressions import RawSQL, OrderBy
RatebookDataEntry.objects.all().order_by(OrderBy(RawSQL("LOWER(data->>%s)", ("manufacturer_name",)), descending=True))
要比较整数字段,可以转换为整数:
RatebookDataEntry.objects.all().order_by(OrderBy(RawSQL("cast(data->>%s as integer)", ("annual_mileage",)), descending=True))
答案 3 :(得分:4)
这是即将推出的功能,已经在Django 2.1中发布,预计将于2018年8月发布。
有关详细信息,请参阅https://code.djangoproject.com/ticket/24747和https://github.com/django/django/pull/8528。
答案 4 :(得分:2)
文档没有提到这种可能性。目前看来你不能使用基于JSON域的order_by。
答案 5 :(得分:1)
这个问题(以及大部分答案)是针对 Django 1.9 的。但是,Django 3.1 和更新版本支持 JSONField
on recent versions MariaDB、MySQL、Oracle、PostgreSQL 和 SQLite。
在 JSON 字段上创建/维护索引的行为可能因数据库引擎而异,但排序应该使用您在问题中的确切语法:
RatebookDataEntry.objects.all().order_by("data__manufacturer_name")
请注意,除非您进行进一步过滤,否则这将包括 manufacturer_name
JSONField 中的 data
键不存在的数据库行。
答案 6 :(得分:0)
我必须按日期进行以下操作(使用to_date
)。假设data
中还有一个称为created_date
的值(例如03.06.2019)。
RatebookDataEntry.objects.all().order_by(
OrderBy(
RawSQL("to_date(values->>%s, 'DD.MM.YYYY')", ("created_date",)),
descending=True,
)
)