Vit*_*t D 6 python django postgresql
我正在尝试ltree在PostgreSQL中使用扩展来构建全文地址搜索引擎.
我的模型看起来像这样(它略微简化):
from django.db import models
class Addresses(models.Model):
name = models.CharField(max_length=255)
path = models.CharField(max_length=255)
Run Code Online (Sandbox Code Playgroud)
因此,此表中的数据将如下所示:
id | name | path
----------------------------
1 | USA | 1
2 | California | 1.2
3 | Los Angeles | 1.2.3
Run Code Online (Sandbox Code Playgroud)
我想对每个实体的聚合名称进行全文搜索.基本上我需要将表中的每一行转换为下一个格式来进行搜索:
id | full_name | path
-------------------------------------------------
1 | USA | 1
2 | California USA | 1.2
3 | Los Angeles California USA | 1.2.3
Run Code Online (Sandbox Code Playgroud)
我这样做,所以用户可以执行像'los ang cali'或类似的查询.使用原始 PostgreSQL查询我没有问题:
SELECT *, ts_rank_cd(to_tsvector('english', full_address), query) AS rank
FROM (SELECT s.id, s.path, array_to_string(array_agg(a.name ORDER BY a.path DESC), ' ') AS full_address
FROM "Addresses" AS s INNER JOIN "Addresses" AS a
ON (a.path @> s.path) GROUP BY s.id, s.path, s.name
) AS subquery, to_tsquery('english', %s) as query WHERE to_tsvector('english', full_address) @@ query
ORDER BY rank DESC;
Run Code Online (Sandbox Code Playgroud)
这工作正常,但在使用RawQuerySet,我不能用之类的东西.filter(),.group_by(),分页等.
在Django中重现它的主要限制是这个JOIN:
JOIN "Addresses" AS a ON (a.path @> s.path)
Run Code Online (Sandbox Code Playgroud)
它是用来连接各元素的所有祖先,然后用它们聚集array_agg(),array_to_string功能,因此这些功能的输出可进一步使用全文搜索.
如果有人有更好的想法如何使用Django ORM实现这种事情,请指教.
您需要一个由 VIEW 支持的非托管模型。
通过将模型的托管元选项设置为 false 来创建非托管模型。
如果为 False,则不会对该模型执行任何数据库表创建或删除操作。如果模型表示现有表或通过其他方式创建的数据库视图,这非常有用。这是 Managed=False 时的唯一区别。模型处理的所有其他方面与正常情况完全相同。这包括
强调我的。
因此,如果您创建一个非托管模型,它可以由数据库上的视图表示,并且您可以访问.filter()它.group_by()。
该视图是您的查询。
CREATE OR REPLACE view full_address_tree AS
SELECT a.*, s.id, s.path, array_to_string(array_agg(a.name ORDER BY a.path DESC), ' ') AS full_address
FROM "Addresses" AS s INNER JOIN "Addresses" AS a
ON (a.path @> s.path) GROUP BY s.id, s.path, s.name
Run Code Online (Sandbox Code Playgroud)
class FullAddressTree(models.Model):
# copy paste the fields from your Addresses model here
sid = models.IntegerField()
sid = models.CharField()
class Meta:
# this is the most important part
managed = False
db_table = 'full_address_tree' # the name of the view
Run Code Online (Sandbox Code Playgroud)
因此,现在您有了一个可用于进行全文搜索的模型,而无需诉诸原始查询。因此,您可以使用 Django ORM 的全部功能。
如果您想要迁移,您会发现 ./manage.py makemigrations 会导致虚拟迁移。./manage.py sqlmigrate 将显示此迁移没有执行任何 sql 查询。
要修复此问题并自动创建视图,请operations向该迁移中的列表添加 RunSQL 调用。
migrations.RunSQL(''' COPY PASTE SQL QUERY FROM ABOVE ''')
Run Code Online (Sandbox Code Playgroud)
您创建的非托管模型是只读的。尝试创建、替换、更新或删除将失败。如果您需要此功能,您将需要一个 INSTEAD 触发器。
| 归档时间: |
|
| 查看次数: |
770 次 |
| 最近记录: |