Django 1.9 JSONField order_by
Django 1.9 JSONField order_by
我有以下包含 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'
并且 data 字段包含此 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")
文档没有提到这种可能性。看来您暂时不能使用基于 JSONfield 的 order_by。
正如 Julien 提到的那样,Django 尚不支持 JSONField
上的排序。但是通过 RawSQL
using PostgreSQL functions for jsonb 是可能的。在 OP 的情况下:
from django.db.models.expressions import RawSQL
RatebookDataEntry.objects.all().order_by(RawSQL("data->>%s", ("manufacturer_name",)))
在 Daniil Ryzhkov answer and 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))
这是一项即将推出的功能,已经添加并将在 Django 2.1 中发布,预计于 2018 年 8 月发布。
详情见https://code.djangoproject.com/ticket/24747 and https://github.com/django/django/pull/8528。
从 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
会return对象的JSON表示,而KeyTextTransform
将 return 对象的值。
例如,如果 data
是 {"test": "stuff"}
,KeyTextTransform
将 return 'stuff'
,而 KeyTransform
将 return '"stuff"'
(可以用json.loads
解析)
我必须执行以下操作才能按日期排序(使用 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,
)
)
这个问题(和大部分答案)是针对 Django 1.9 的。但是,Django 版本 3.1 和更高版本 支持 MariaDB、MySQL、Oracle、PostgreSQL 和 SQLite 的 JSONField
on recent versions。
JSON 字段上 creating/maintaining 索引的行为可能因数据库引擎而异,但排序应与您在问题中使用的语法完全一致:
RatebookDataEntry.objects.all().order_by("data__manufacturer_name")
请注意,除非您进行进一步过滤,否则这将包括 data
JSON 字段中 manufacturer_name
键不存在的数据库行。
我有以下包含 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'
并且 data 字段包含此 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")
文档没有提到这种可能性。看来您暂时不能使用基于 JSONfield 的 order_by。
正如 Julien 提到的那样,Django 尚不支持 JSONField
上的排序。但是通过 RawSQL
using PostgreSQL functions for jsonb 是可能的。在 OP 的情况下:
from django.db.models.expressions import RawSQL
RatebookDataEntry.objects.all().order_by(RawSQL("data->>%s", ("manufacturer_name",)))
在 Daniil Ryzhkov answer and 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))
这是一项即将推出的功能,已经添加并将在 Django 2.1 中发布,预计于 2018 年 8 月发布。
详情见https://code.djangoproject.com/ticket/24747 and https://github.com/django/django/pull/8528。
从 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
会return对象的JSON表示,而KeyTextTransform
将 return 对象的值。
例如,如果 data
是 {"test": "stuff"}
,KeyTextTransform
将 return 'stuff'
,而 KeyTransform
将 return '"stuff"'
(可以用json.loads
解析)
我必须执行以下操作才能按日期排序(使用 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,
)
)
这个问题(和大部分答案)是针对 Django 1.9 的。但是,Django 版本 3.1 和更高版本 支持 MariaDB、MySQL、Oracle、PostgreSQL 和 SQLite 的 JSONField
on recent versions。
JSON 字段上 creating/maintaining 索引的行为可能因数据库引擎而异,但排序应与您在问题中使用的语法完全一致:
RatebookDataEntry.objects.all().order_by("data__manufacturer_name")
请注意,除非您进行进一步过滤,否则这将包括 data
JSON 字段中 manufacturer_name
键不存在的数据库行。