这个 SQL 语句有 django ORM 版本吗?

Posted

技术标签:

【中文标题】这个 SQL 语句有 django ORM 版本吗?【英文标题】:Is there a django ORM version of this SQL statement? 【发布时间】:2016-04-15 16:02:09 【问题描述】:

使用 Django 1.9 和 Postgres 9.4。

我有一个名为 json_field 的 jsonb 字段。 json_field 可以包含密钥 title,它可能看起来像 'the cow jumped over the moon'

所以我想搜索title 包含moon 的行。

使用以下原始 SQL 可以正常工作

SELECT * FROM web_file where (json_field ->> 'title')::text LIKE '%moon%';

但我宁愿使用 Django ORM。

编辑:

我想尝试一下(正如@kloddant 所指出的那样)

title = WebFile.objects.filter(json_field__title__contains='moon')

但它给出了以下错误

DataError: invalid input syntax for type json
LINE 1: ...le" WHERE "web_file"."json_field" -> 'title' @> 'moon' ORD...
                                                            ^
DETAIL:  Token "moon" is invalid.
CONTEXT:  JSON data, line 1: moon

这里是相关的models.py

from django.contrib.postgres.fields import JSONField

class WebFile(MPTTModel):
    json_field = JSONField(null=True, blank=True, default=dict())

这可能是 django 模型和 MPTTModel 之间的冲突,尽管我对此表示怀疑?

【问题讨论】:

JSONField 字段类型从何而来?它不是 Django 的一部分,也不是 MPTT 的一部分。 @MadWombat 它在 Django 1.9 中的新功能docs.djangoproject.com/es/1.9/ref/contrib/postgres/fields/… 您可能想阅读文档。 JSONField 不是字符串,因此看起来__contains 过滤器可能与字符串不同。 docs.djangoproject.com/es/1.9/ref/contrib/postgres/fields/… 阅读更多,看起来你需要将字典传递给__contains 【参考方案1】:

https://docs.djangoproject.com/es/1.9/ref/contrib/postgres/fields/

你会做这样的事情:

WebFile.objects.filter(json_field__title__contains='moon')

【讨论】:

我也这么认为,但它似乎不起作用:` DataError: invalid input syntax for type json LINE 1: ...le" WHERE "web_file"."json_field" -> 'title' @> 'moon' ORD... ^ DETAIL: token "moon" is invalid. CONTEXT: JSON data, line 1: moon ` 这很奇怪。 WebFile.object.filter(json_field__title='moon') 工作吗(我的意思是工作是否找到标题为“月亮”的东西,我意识到它不会给你你想要的东西)?也许这与__contains有关?【参考方案2】:
title = WebFile.objects.filter(title__icontains=moon)

当然,您必须先创建 WebFile 模型,然后从 models.py 文件中将其导入页面顶部。

【讨论】:

这不起作用,因为title 包含在json_field 如果你的数据库字段中有一个 json 对象,那么我会考虑重组你的数据库,如果可能的话,这样所有的 json 数据都在一个单独的表中,该表使用一个链接到 webfile 表外键。 有些用例是应用程序用户希望创建自己的无模式键值对,但我不想为每个用户创建一个新表。我认为我的用例与 Postgres 9.4 jsonb 可以做的非常一致。 @kloddant 不需要重组。 JSON 字段是 PostgreSQL 的一个特性,有很多真实的用例。它不能用来代替 NoSQL 数据库,但在某些情况下它肯定是有用的,尤其是 Django 内置的 Postgres 字段。【参考方案3】:

您没有使用来自django.contrib.postgres.fieldsJSONField 吗?在那种情况下,它只是like this:

WebFile.objects.filter(json_field__title__contains='moon')

可以发一下相关的models.py吗?此外,如果您不使用 django.contrib.postgres.fields 并依赖默认模型(例如手动扩展 CharField 或其他东西),您将会遇到困难。

【讨论】:

我已经发布了model.py 您尝试过我发布的方法吗?问题是您无法过滤title 上的对象,因为title 不是WebFile 的属性。此外,您的 default 应该是可调用的。使用dict 作为空默认值。从文档中:“错误地使用 default= 创建了一个可变的默认值,在 JSONField 的所有实例之间共享。” 是的,我已经尝试过您的方法,但我收到了一个错误(我已将错误包含在我的问题中)。感谢您在默认值上的指针。

以上是关于这个 SQL 语句有 django ORM 版本吗?的主要内容,如果未能解决你的问题,请参考以下文章

Django 第十课 1.ORM模型

执行Django原生的sql语句

Django-orm操作的基础认识

备战Django之ORM模型(增删改查)

Django-.模型层

如何查看Django ORM执行的SQL语句