[英]Django 1.9 JSONField order_by
I have the following django model that contains JSONField:我有以下包含 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'
And data field contains this json:数据字段包含此 json:
{
"annual_mileage": 15000,
"description": "LEON DIESEL SPORT COUPE",
"body_style": "Coupe",
"range_name": "LEON",
"co2_gkm_max": 122,
"manufacturer_name": "SEAT"
}
Can I sort queryset by one of the data fields?我可以按数据字段之一对查询集进行排序吗? This query doesn't work.此查询不起作用。
RatebookDataEntry.objects.all().order_by("data__manufacturer_name")
As Julien mentioned ordering on JSONField
is not yet supported in Django.正如 Julien 提到的,Django 尚不支持对JSONField
排序。 But it's possible via RawSQL
using PostgreSQL functions for jsonb .但是可以通过RawSQL
使用RawSQL
PostgreSQL 函数。 In OP's case:在 OP 的情况下:
from django.db.models.expressions import RawSQL
RatebookDataEntry.objects.all().order_by(RawSQL("data->>%s", ("manufacturer_name",)))
Since Django 1.11, django.contrib.postgres.fields.jsonb.KeyTextTransform
can be used instead of RawSQL
从 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')
On Django 1.10, you'll have to subclass KeyTransform
yourself:在 Django 1.10 上,你必须自己KeyTransform
:
from django.contrib.postgres.fields.jsonb import KeyTransform
class KeyTextTransform(KeyTransform):
operator = '->>'
nested_operator = '#>>'
_output_field = TextField()
Note: the difference between KeyTransform
and KeyTextTransform
is that KeyTransform
will return the JSON representation of the object, whereas KeyTextTransform
will return the value of the object.注:之间的区别KeyTransform
和KeyTextTransform
是KeyTransform
将返回对象的JSON表示,而KeyTextTransform
将返回对象的值。
For example, if data
is {"test": "stuff"}
, KeyTextTransform
will return 'stuff'
, whereas KeyTransform
will return '"stuff"'
(which can be parsed by json.loads
)例如,如果data
是{"test": "stuff"}
, KeyTextTransform
将返回'stuff'
,而KeyTransform
将返回'"stuff"'
(可以通过json.loads
解析)
Following Daniil Ryzhkov answer and Eugene Prikazchikov comment, you should be able to sort ASC and DESC on JSON data fields without annotating your queryset, by using both RawSQL
and OrderBy
.按照Daniil Ryzhkov 的回答和Eugene Prikazchikov 的评论,您应该能够通过使用RawSQL
和OrderBy
对 JSON 数据字段的 ASC 和 DESC 进行排序,而无需注释您的RawSQL
。 Also, you can perform case insensitive sorting by adding LOWER
:此外,您可以通过添加LOWER
来执行不区分大小写的排序:
from django.db.models.expressions import RawSQL, OrderBy
RatebookDataEntry.objects.all().order_by(OrderBy(RawSQL("LOWER(data->>%s)", ("manufacturer_name",)), descending=True))
To compare integers fields, you can cast as integer:要比较整数字段,您可以将其转换为整数:
RatebookDataEntry.objects.all().order_by(OrderBy(RawSQL("cast(data->>%s as integer)", ("annual_mileage",)), descending=True))
This is an upcoming feature which has already been added and will be released in Django 2.1, expected release of August 2018.这是即将推出的功能,已经添加并将在 Django 2.1 中发布,预计将于 2018 年 8 月发布。
See https://code.djangoproject.com/ticket/24747 and https://github.com/django/django/pull/8528 for details.有关详细信息,请参阅https://code.djangoproject.com/ticket/24747和https://github.com/django/django/pull/8528 。
The documentation does not mention this possibility.文档没有提到这种可能性。 It seems you cannot use order_by based on a JSONfield for the moment.看来您暂时不能使用基于 JSONfield 的 order_by。
This question (and most of the answers) are for Django 1.9.这个问题(以及大部分答案)是针对 Django 1.9 的。 However, Django versions 3.1 and newer support JSONField
on recent versions of MariaDB, MySQL, Oracle, PostgreSQL, and SQLite.但是, Django 3.1 和更新版本在 MariaDB、MySQL、Oracle、PostgreSQL 和 SQLite 的最新版本上支持JSONField
。
The behavior around creating/maintaining indexes on JSON fields may vary across database engines, but ordering should work with the exact syntax you have in your question:在 JSON 字段上创建/维护索引的行为可能因数据库引擎而异,但排序应该使用您在问题中的确切语法:
RatebookDataEntry.objects.all().order_by("data__manufacturer_name")
Note that unless you do further filtering, this will include database rows where the manufacturer_name
key in the data
JSONField does not exist.请注意,除非您进行进一步过滤,否则这将包括data
JSONField 中的manufacturer_name
键不存在的数据库行。
I had to do the following to order by date (using to_date
).我必须执行以下操作才能按日期排序(使用to_date
)。 Assuming there's another value in data
called created_date
(eg 03.06.2019).假设有一个在另一个值data
称为created_date
(如2019年6月3日)。
RatebookDataEntry.objects.all().order_by(
OrderBy(
RawSQL("to_date(values->>%s, 'DD.MM.YYYY')", ("created_date",)),
descending=True,
)
)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.