【问题标题】:Django 1.9 JSONField order_byDjango 1.9 JSONField order_by
【发布时间】:2016-08-07 02:36:19
【问题描述】:

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

【问题讨论】:

  • 不是我所知道的(在查询集上),但这种情况向我表明,您实际上可能需要一个用于“数据”而不是 json 的对象模型
  • 顺便说一句,使用default=list 而不是default=[],否则你最终会得到不同实例之间共享的相同列表。

标签: python django django-1.9 django-jsonfield


【解决方案1】:

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

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

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

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

【讨论】:

    【解决方案2】:

    我必须执行以下操作才能按日期订购(使用 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,
            )
        )
    

    【讨论】:

      【解决方案3】:

      从 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()
      

      注意:KeyTransformKeyTextTransform 的区别在于KeyTransform 将返回对象的JSON 表示,而KeyTextTransform 将返回对象的值。

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

      【讨论】:

      • 定义我需要的东西
      • 这应该是首选答案
      • 我的 json 字段有以下格式的数据,如何使用它根据字典中的第一个 IP 地址进行排序?
      【解决方案4】:

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

      详情请参阅https://code.djangoproject.com/ticket/24747https://github.com/django/django/pull/8528

      【解决方案5】:

      Daniil Ryzhkov 回答和Eugene Prikazchikov 评论之后,您应该能够使用RawSQLOrderBy 对JSON 数据字段进行ASC 和DESC 排序,而无需注释您的查询集。此外,您可以通过添加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))
      

      【讨论】:

        【解决方案6】:

        正如 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",)))
        

        【讨论】:

        • 如果你想要DESC排序,你可以引入注释字段并按它排序。像这样: RatebookDataEntry.objects.annotate(manufacturer_name=RawSQL("data->>%s", ("manufacturer_name",)).order_by("-manufacturer_name")
        • 以防万一有人只查看已接受的答案,这是 Django 2.1 中的一个功能,请参阅我的答案以获取链接。
        • 这对 MySQL 不起作用,对 MySQL 有什么解决方法吗?
        • 如果您想订购数值,请使用 -> 而不是 ->>。 (->>gets JSON object field as text)
        【解决方案7】:

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

        【讨论】:

          猜你喜欢
          • 2019-07-28
          • 2016-05-30
          • 2016-08-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-07-23
          • 2013-01-01
          • 1970-01-01
          相关资源
          最近更新 更多