如何使用 Django 功能而不是所有键来索引刚刚选择的 json 键?

Posted

技术标签:

【中文标题】如何使用 Django 功能而不是所有键来索引刚刚选择的 json 键?【英文标题】:How to index just selected json key using Django functionality instead of all keys? 【发布时间】:2020-04-14 18:57:10 【问题描述】:

我有下一个模型:

from django.contrib.postgres.fields import JSONField
from django.contrib.postgres.fields.jsonb import KeyTextTransform
from django.contrib.postgres.indexes import GinIndex
from django.contrib.postgres.search import SearchVectorField, SearchVector
from django.db import models


class ProfileUser(models.Model):
    name = JSONField()
    search_vector = SearchVectorField(null=True)

    class Meta:
        indexes = [GinIndex(fields=["search_vector"], name="user_full_name_gin_idx")]

    def save(self, *args, **kwargs):
        super(ProfileUser, self).save(*args, **kwargs)
        ProfileUser.objects.filter(pk=self.pk).update(search_vector=SearchVector('name'))

        # I have tried this, but this does not work.
        # ProfileUser.objects.filter(pk=self.pk).update(search_vector=SearchVector(KeyTextTransform('name', 'name')))

name 看起来像['name': 'Random Name', 'lang': 'en', 'name': 'Какое-то Имя', 'lang': 'ru']

目前上面的代码索引namelang 键。是否可以使用 Django 仅索引 name 键?我found 如何直接使用 SQL 来解决这个问题,但我只想知道,是否可以通过 Django 来解决。

我使用 Django 2.2 和 PostgreSQL 12。

【问题讨论】:

【参考方案1】:

在 PostgreSQL 中,允许在部分 JSON 结构字段上创建索引的功能称为 expression index。它需要与GIN索引一起使用才能达到预期的效果。这样的用法在jsonbdocumentation中有简单的提及:

CREATE INDEX idxgintags ON api USING GIN ((jdoc -> 'tags'));

据我所知,目前(2020 年 12 月)在 Django 中创建此类索引的唯一方法是手动发出 SQL 语句。

但是,有一个开放的ticket 要求向 Django 添加对表达式索引的支持。该功能已被接受,但还没有补丁,并且一年多没有更新票证。

【讨论】:

在此 PR 的 3.2 中添加了支持:github.com/django/django/pull/11929 但是,我仍然对正确的语法感到困惑。【参考方案2】:

Functional indexes 将于 4 月在 Django 3.2 中可用。这最终应该允许从 Django 构建所需的索引。

【讨论】:

【参考方案3】:

是的,有可能,您可以在此处阅读 django 索引文档: https://docs.djangoproject.com/en/3.0/ref/models/indexes/

改变这一行:

indexes = [GinIndex(fields=["search_vector"], name="user_full_name_gin_idx")]

到这里:

indexes = [GinIndex(fields=["name"], name="user_full_name_gin_idx")]

【讨论】:

这无济于事,因为fields=["name"] 包含两个字段(namelang)。 fields 表示 field names of model(不是 JSON 的键)。

以上是关于如何使用 Django 功能而不是所有键来索引刚刚选择的 json 键?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Django 中同一个表的多个外键来管理删除?

django css 不会从索引 url 而不是任何其他 url 加载

Django ORM:如何根据所有记录中的列获取唯一记录(需要模型对象而不是特定值对象)

如何在 django 中指定索引类型? (btree 与哈希等)

检查请求的用户是不是是 django 中的所有者

字典值不能通过在 django 模板中使用它们的对应键来迭代[重复]