是否可以在 Django SearchVectorField 中保留一个连接字段?

Posted

技术标签:

【中文标题】是否可以在 Django SearchVectorField 中保留一个连接字段?【英文标题】:Is it possible to persist a joined field in Djangos SearchVectorField? 【发布时间】:2018-02-02 11:09:38 【问题描述】:

是否可以使用 Django 的 SearchVectorField 持久化连接字段以进行全文搜索?

例如:

class P(models.Model):
    brand = models.ForeignKey(Brand, on_delete=models.CASCADE)
    search_vector = SearchVectorField(null=True, blank=True)

代码:

p = P.objects.get(id=1)
p.search_vector = SearchVector('brand__name')
p.save()

引发此异常:

FieldError: Joined field references are not permitted in this query

如果这是不可能的,您如何提高联合注释查询的性能?

【问题讨论】:

【参考方案1】:

我找到了解决您的问题的方法:

p = P.objects.annotate(brand_name=SearchVector('brand__name')).get(id=1)
p.search_vector = p.brand_name
p.save()

2018 年 6 月 29 日更新

据官方documentation报道:

如果您只是更新一条记录并且不需要对模型对象做任何事情,最有效的方法是调用 update(),而不是将模型对象加载到内存中。

使用 update() 还可以防止在加载对象和调用 save() 之间的短时间内数据库中的某些内容可能发生变化的竞争条件。

最后,要意识到 update() 在 SQL 级别进行更新,因此不会在模型上调用任何 save() 方法,也不会发出 pre_save 或 post_save 信号(这是调用 Model 的结果.save())。

所以在这种情况下,您可以使用此查询对数据库执行单个 SQL 查询:

from django.contrib.postgres.search import SearchVector
from django.db.models import F

P.objects.annotate(
    brand_name=SearchVector('brand__name')
).filter(
    id=1
).update(
    search_vector=F('brand_name')
)

【讨论】:

你不是用那个.get(id=1) 做一个冗余的数据库查询吗?我也在寻找一种解决方案,从外来关系构建搜索向量。 @Nad 我已经用仅在 db 上执行一个查询的解决方案更新了我的答案,但请阅读有关保存和更新之间区别的文档 感谢您。我的问题是我已经有一个模型实例,并且我想从 post_save 信号更新 search_vector。我在这里发布了一个问题***.com/questions/51105651/… 在这里找到了你的答案! ***.com/questions/42679743/… 太棒了,谢谢 @nad 我为您的问题找到了有用的答案。如果它有效,请投票。

以上是关于是否可以在 Django SearchVectorField 中保留一个连接字段?的主要内容,如果未能解决你的问题,请参考以下文章