---
title: "搜索"
version: 5.0
locale: zh-hans
source: https://docs.djangoproject.com/zh-hans/5.0/topics/db/search/
canonical: https://djangodocs.dev/zh-hans/5.0/topics/db/search/
---
# 搜索

Web 应用的常见任务是根据用户输入查出数据库中的数据。在一个简单例子中，会是通过分类筛选一个对象列表。一个更复杂的用例可能会要求根据重量，分类，多语言等筛选对象。本文介绍了一些常见用例和你能使用的工具。

我们会引用与 [执行查询](/zh-hans/5.0/topics/db/queries/) 中一样的模型。

## 用例

### 标准文本查询

文本字段具有一些匹配操作的选项。例如，您可能希望允许按以下方式查找作者：

```pycon
>>> Author.objects.filter(name__contains="Terry")
[<Author: Terry Gilliam>, <Author: Terry Jones>]
```

这是一种非常简陋的方案，因为它要求用户必须知道用户名中包含的字符串。大小写不敏感的匹配 ([`icontains`](/zh-hans/5.0/ref/models/querysets/#std-fieldlookup-icontains)) 不失为一种更好的方案，但优化的程度有限。

### 一个更高级的数据库比较函数

若你使用的是 PostgreSQL，Django 提供了 [数据特殊筛选工具](/zh-hans/5.0/ref/contrib/postgres/search/) 帮助你巧妙利用更复杂的查询条件。其它数据库也有不同的筛选工具，可能是通过插件或用户自定义函数实现的。Django 此时还没有为他们提供任何支持。我们会用来自 PostgreSQL 的实例来证明其包含的功能函数。

> **在其它数据库中搜索**
>
> 所有由 [`django.contrib.postgres`](/zh-hans/5.0/ref/contrib/postgres/#module-django.contrib.postgres) 提供的筛选工具均基于 [自定义查询](/zh-hans/5.0/ref/models/lookups/) 和 [数据库函数](/zh-hans/5.0/ref/models/database-functions/) 实现。根据你使用的数据库，你应该构建响应的查询，实现类似的 API。若有某个东西无法以这种方式实现，请新建一个工单。

在上面的示例中，我们确定不区分大小写的查找更有用。当处理非英语姓名时，进一步的改进是使用 [`非重音比较`](/zh-hans/5.0/ref/contrib/postgres/lookups/#std-fieldlookup-unaccent)：

```pycon
>>> Author.objects.filter(name__unaccent__icontains="Helen")
[<Author: Helen Mirren>, <Author: Helena Bonham Carter>, <Author: Hélène Joy>]
```

这展开了另一个关于通过名字的不同拼写进行比较的讨论。但这种比较是不对称的 —— 筛选 `Helen` 能拿到 `Helena` 或 `Hélène`，但反着来却不行。还有一个选项允许使用 [`trigram_similar`](/zh-hans/5.0/ref/contrib/postgres/lookups/#std-fieldlookup-trigram_similar) 比较，这回比较字母的序列。

例如：

```pycon
>>> Author.objects.filter(name__unaccent__lower__trigram_similar="Hélène")
[<Author: Helen Mirren>, <Author: Hélène Joy>]
```

现在还有一个问题 —— 名字 "Helena Bonham Carter" 有点太长了，以至于没有显示。三元搜索综合考虑了三种字母的所有组合形式，并同时再查询和源字符串中比较了出现的次数。对于长名字，源字符串中包含了更多的组合方式，所以其不再被认为是一种近似匹配。

要基于你提供的特定数据集合选择一个合适的比较函数，例如依据使用的语言和待搜索的文本。我们见过的所有例子都是关于短字符串的，这使得用户可以输入与源数据关联较大（根据不同的定义）的内容。

### 文档搜索

标准数据库操作对于大量文本搜索来说太过简陋了。虽然上面的示例可以看作是对字符串的操作，但是全文搜索查看的是实际的单词。依据所使用的系统，可以采用下面的某些方法：

- 忽略 “停止单词”，例如 "a"，"the"，"and"。
- 词干化，这样 "pony" 和 "ponies" 会被认为是一样的。
- 根据不同的标准为单词设置权重，例如其在文本中出现的频率，或所属字段（如标题或关键字）的重要性。

使用搜索软件有很多选项，最常见的有 [Elastic](https://www.elastic.co/) 和 [Solr](https://solr.apache.org/)。它们都是基于全文搜索的解决方案。要用它们搜索来自 Django 模型的数据，你需要一个抽象层，将数据（包括对数据库 id 的指针）转换为文本文档。当使用该引擎的某次搜索返回了一份文档，你可以在数据库中查看它。有很多第三方库被设计为处理这种问题。

#### PostgreSQL 支持

PostgreSQL 内置了其专属的全文本搜索实现。虽然并不像其它搜索引擎那样强大，但它的优点是内置在数据库中，所以它能很方便的与其它关联查询条件进行联合查询，如按分类查询。

[`django.contrib.postgres`](/zh-hans/5.0/ref/contrib/postgres/#module-django.contrib.postgres) 模块提供了一些辅助工具来执行这些查询。例如，一个查询可以选择所有提到 "cheese" 的博客条目：

```pycon
>>> Entry.objects.filter(body_text__search="cheese")
[<Entry: Cheese on Toast recipes>, <Entry: Pizza recipes>]
```

您还可以根据字段的组合和相关模型进行筛选：

```pycon
>>> Entry.objects.annotate(
...     search=SearchVector("blog__tagline", "body_text"),
... ).filter(search="cheese")
[
    <Entry: Cheese on Toast recipes>,
    <Entry: Pizza Recipes>,
    <Entry: Dairy farming in Argentina>,
]
```

参阅 `contrib.postgres` [全文搜索](/zh-hans/5.0/ref/contrib/postgres/search/) 文档获取全部细节。
