16

我有以下包含 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")
4

7 回答 7

26

正如 Julien 提到JSONField的,Django 尚不支持订购。但是可以通过对 jsonbRawSQL使用PostgreSQL 函数来实现。在 OP 的情况下:

from django.db.models.expressions import RawSQL
RatebookDataEntry.objects.all().order_by(RawSQL("data->>%s", ("manufacturer_name",)))
于 2016-05-22T17:14:59.820 回答
17

从 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将返回对象的值。

例如,如果data{"test": "stuff"}KeyTextTransform将返回'stuff',而KeyTransform将返回'"stuff"'(可以通过解析json.loads

于 2018-04-26T15:18:19.777 回答
10

按照Daniil Ryzhkov 的回答和Eugene Prikazchikov 的评论,您应该能够在 JSON 数据字段上对 ASC 和 DESC 进行排序,而无需注释您的查询集,同时使用RawSQLOrderBy。此外,您可以通过添加执行不区分大小写的排序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))
于 2017-05-19T10:09:57.463 回答
6

这是一个即将推出的功能,已经添加并将在 Django 2.1 中发布,预计 2018 年 8 月发布。

有关详细信息,请参阅https://code.djangoproject.com/ticket/24747https://github.com/django/django/pull/8528

于 2018-02-05T11:00:13.650 回答
6

这个问题(以及大多数答案)适用于 Django 1.9。但是,Django 版本 3.1 和更新版本支持MariaDB、MySQL、Oracle、PostgreSQL 和 SQLite 的JSONField 最新版本。

在 JSON 字段上创建/维护索引的行为可能因数据库引擎而异,但排序应该与您在问题中的确切语法一起使用:

RatebookDataEntry.objects.all().order_by("data__manufacturer_name")

请注意,除非您进行进一步过滤,否则这将包括 JSONField 中的manufacturer_namedata不存在的数据库行。

于 2021-01-09T15:48:14.037 回答
3

文档没有提到这种可能性。看来您目前不能使用基于 JSON 字段的 order_by。

于 2016-04-15T08:36:20.070 回答
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,
        )
    )
于 2019-06-03T09:33:13.520 回答