简体   繁体   English

Django 1.9 JSONField order_by

[英]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.注:之间的区别KeyTransformKeyTextTransformKeyTransform将返回对象的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 的评论,您应该能够通过使用RawSQLOrderBy对 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/24747https://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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM