{"title":"搜索","version":"4.1","locale":"zh-hans","docname":"topics/db/search","url":"/zh-hans/4.1/topics/db/search/","canonical":"https://djangodocs.dev/zh-hans/4.1/topics/db/search/","summary":"Web 应用的常见任务是根据用户输入查出数据库中的数据。在一个简单例子中，会是通过分类筛选一个对象列表。一个更复杂的用例可能会要求根据重量，分类，多语言等筛选对象。本文介绍了一些常见用例和你能使用的工具。 我们会引用与 执行查询 中一样的模型。 用例 Link to this heading # 标准文本查询 Link to…","html":"<h1>搜索<a class=\"heading-anchor\" href=\"#search\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>Web 应用的常见任务是根据用户输入查出数据库中的数据。在一个简单例子中，会是通过分类筛选一个对象列表。一个更复杂的用例可能会要求根据重量，分类，多语言等筛选对象。本文介绍了一些常见用例和你能使用的工具。</p>\n<p>我们会引用与 <a class=\"reference internal\" href=\"/zh-hans/4.1/topics/db/queries/\"><span class=\"doc\">执行查询</span></a> 中一样的模型。</p>\n<section id=\"use-cases\">\n<h2>用例<a class=\"heading-anchor\" href=\"#use-cases\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<section id=\"standard-textual-queries\">\n<h3>标准文本查询<a class=\"heading-anchor\" href=\"#standard-textual-queries\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>文本字段能通过匹配运算进行筛选。例如，你可能会这样查找一个作者:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Author</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">filter</span><span class=\"p\">(</span><span class=\"n\">name__contains</span><span class=\"o\">=</span><span class=\"s1\">&#39;Terry&#39;</span><span class=\"p\">)</span>\n<span class=\"go\">[&lt;Author: Terry Gilliam&gt;, &lt;Author: Terry Jones&gt;]</span>\n</code></pre></div>\n<p>这是一种非常简陋的方案，因为它要求用户必须知道用户名中包含的字符串。大小写不敏感的匹配 (<a class=\"reference internal\" href=\"/zh-hans/4.1/ref/models/querysets/#std-fieldlookup-icontains\"><code class=\"xref std std-lookup docutils literal notranslate\"><span class=\"pre\">icontains</span></code></a>) 不失为一种更好的方案，但优化的程度有限。</p>\n</section>\n<section id=\"a-database-s-more-advanced-comparison-functions\">\n<h3>一个更高级的数据库比较函数<a class=\"heading-anchor\" href=\"#a-database-s-more-advanced-comparison-functions\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>若你使用的是 PostgreSQL，Django 提供了 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/postgres/search/\"><span class=\"doc\">数据特殊筛选工具</span></a> 帮助你巧妙利用更复杂的查询条件。其它数据库也有不同的筛选工具，可能是通过插件或用户自定义函数实现的。Django 此时还没有为他们提供任何支持。我们会用来自 PostgreSQL 的实例来证明其包含的功能函数。</p>\n<aside class=\"admonition-searching-in-other-databases admonition\">\n<p class=\"admonition-title\">在其它数据库中搜索</p>\n<p>所有由 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/postgres/#module-django.contrib.postgres\" title=\"django.contrib.postgres: PostgreSQL-specific fields and features\"><code class=\"xref py py-mod docutils literal notranslate\"><span class=\"pre\">django.contrib.postgres</span></code></a> 提供的筛选工具均基于 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/models/lookups/\"><span class=\"doc\">自定义查询</span></a> 和 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/models/database-functions/\"><span class=\"doc\">数据库函数</span></a> 实现。根据你使用的数据库，你应该构建响应的查询，实现类似的 API。若有某个东西无法以这种方式实现，请新建一个工单。</p>\n</aside>\n<p>在上面的例子中，我们可以确认大小写不敏感的查询会更实用一些。当处理英文以外的名字时，可以用 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/postgres/lookups/#std-fieldlookup-unaccent\"><code class=\"xref std std-lookup docutils literal notranslate\"><span class=\"pre\">无重音比较</span></code></a> 来优化:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Author</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">filter</span><span class=\"p\">(</span><span class=\"n\">name__unaccent__icontains</span><span class=\"o\">=</span><span class=\"s1\">&#39;Helen&#39;</span><span class=\"p\">)</span>\n<span class=\"go\">[&lt;Author: Helen Mirren&gt;, &lt;Author: Helena Bonham Carter&gt;, &lt;Author: Hélène Joy&gt;]</span>\n</code></pre></div>\n<p>这展开了另一个关于通过名字的不同拼写进行比较的讨论。但这种比较是不对称的 —— 筛选 <code class=\"docutils literal notranslate\"><span class=\"pre\">Helen</span></code> 能拿到 <code class=\"docutils literal notranslate\"><span class=\"pre\">Helena</span></code> 或 <code class=\"docutils literal notranslate\"><span class=\"pre\">Hélène</span></code>，但反着来却不行。还有一个选项允许使用 <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/postgres/lookups/#std-fieldlookup-trigram_similar\"><code class=\"xref std std-lookup docutils literal notranslate\"><span class=\"pre\">trigram_similar</span></code></a> 比较，这回比较字母的序列。</p>\n<p>例如：</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Author</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">filter</span><span class=\"p\">(</span><span class=\"n\">name__unaccent__lower__trigram_similar</span><span class=\"o\">=</span><span class=\"s1\">&#39;Hélène&#39;</span><span class=\"p\">)</span>\n<span class=\"go\">[&lt;Author: Helen Mirren&gt;, &lt;Author: Hélène Joy&gt;]</span>\n</code></pre></div>\n<p>现在还有一个问题 —— 名字 &quot;Helena Bonham Carter&quot; 有点太长了，以至于没有显示。三元搜索综合考虑了三种字母的所有组合形式，并同时再查询和源字符串中比较了出现的次数。对于长名字，源字符串中包含了更多的组合方式，所以其不再被认为是一种近似匹配。</p>\n<p>要基于你提供的特定数据集合选择一个合适的比较函数，例如依据使用的语言和待搜索的文本。我们见过的所有例子都是关于短字符串的，这使得用户可以输入与源数据关联较大（根据不同的定义）的内容。</p>\n</section>\n<section id=\"document-based-search\">\n<h3>文档搜索<a class=\"heading-anchor\" href=\"#document-based-search\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>标准数据库操作对于大量文本搜索来说太过简陋了。虽然上面的示例可以看作是对字符串的操作，但是全文搜索查看的是实际的单词。依据所使用的系统，可以采用下面的某些方法：</p>\n<ul class=\"simple\">\n<li><p>忽略 “停止单词”，例如 &quot;a&quot;，&quot;the&quot;，&quot;and&quot;。</p></li>\n<li><p>词干化，这样 &quot;pony&quot; 和 &quot;ponies&quot; 会被认为是一样的。</p></li>\n<li><p>根据不同的标准为单词设置权重，例如其在文本中出现的频率，或所属字段（如标题或关键字）的重要性。</p></li>\n</ul>\n<p>使用搜索软件有很多选项，最常见的有 <a class=\"reference external\" href=\"https://www.elastic.co/\">Elastic</a> 和 <a class=\"reference external\" href=\"https://solr.apache.org/\">Solr</a>。它们都是基于全文搜索的解决方案。要用它们搜索来自 Django 模型的数据，你需要一个抽象层，将数据（包括对数据库 id 的指针）转换为文本文档。当使用该引擎的某次搜索返回了一份文档，你可以在数据库中查看它。有很多第三方库被设计为处理这种问题。</p>\n<section id=\"postgresql-support\">\n<h4>PostgreSQL 支持<a class=\"heading-anchor\" href=\"#postgresql-support\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>PostgreSQL 内置了其专属的全文本搜索实现。虽然并不像其它搜索引擎那样强大，但它的优点是内置在数据库中，所以它能很方便的与其它关联查询条件进行联合查询，如按分类查询。</p>\n<p><a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/postgres/#module-django.contrib.postgres\" title=\"django.contrib.postgres: PostgreSQL-specific fields and features\"><code class=\"xref py py-mod docutils literal notranslate\"><span class=\"pre\">django.contrib.postgres</span></code></a> 模块提供了一些助手函数来执行这些查询。例如，查询可能筛选出所有提到了 &quot;cheese&quot; 的博客条目:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Entry</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">filter</span><span class=\"p\">(</span><span class=\"n\">body_text__search</span><span class=\"o\">=</span><span class=\"s1\">&#39;cheese&#39;</span><span class=\"p\">)</span>\n<span class=\"go\">[&lt;Entry: Cheese on Toast recipes&gt;, &lt;Entry: Pizza recipes&gt;]</span>\n</code></pre></div>\n<p>你也可以在联合字段或关联模型上进行筛选:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">Entry</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">annotate</span><span class=\"p\">(</span>\n<span class=\"gp\">... </span>    <span class=\"n\">search</span><span class=\"o\">=</span><span class=\"n\">SearchVector</span><span class=\"p\">(</span><span class=\"s1\">&#39;blog__tagline&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;body_text&#39;</span><span class=\"p\">),</span>\n<span class=\"gp\">... </span><span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">filter</span><span class=\"p\">(</span><span class=\"n\">search</span><span class=\"o\">=</span><span class=\"s1\">&#39;cheese&#39;</span><span class=\"p\">)</span>\n<span class=\"go\">[</span>\n<span class=\"go\">    &lt;Entry: Cheese on Toast recipes&gt;,</span>\n<span class=\"go\">    &lt;Entry: Pizza Recipes&gt;,</span>\n<span class=\"go\">    &lt;Entry: Dairy farming in Argentina&gt;,</span>\n<span class=\"go\">]</span>\n</code></pre></div>\n<p>参阅 <code class=\"docutils literal notranslate\"><span class=\"pre\">contrib.postgres</span></code> <a class=\"reference internal\" href=\"/zh-hans/4.1/ref/contrib/postgres/search/\"><span class=\"doc\">全文搜索</span></a> 文档获取全部细节。</p>\n</section>\n</section>\n</section>","rootId":"search","toc":[{"title":"用例","anchor":"use-cases","children":[{"title":"标准文本查询","anchor":"standard-textual-queries","children":[]},{"title":"一个更高级的数据库比较函数","anchor":"a-database-s-more-advanced-comparison-functions","children":[]},{"title":"文档搜索","anchor":"document-based-search","children":[{"title":"PostgreSQL 支持","anchor":"postgresql-support","children":[]}]}]}],"breadcrumbs":[{"docname":"topics/index","title":"使用 Django","url":"/zh-hans/4.1/topics/"},{"docname":"topics/db/index","title":"模型和数据库","url":"/zh-hans/4.1/topics/db/"}],"prev":{"docname":"topics/db/aggregation","title":"聚合","url":"/zh-hans/4.1/topics/db/aggregation/"},"next":{"docname":"topics/db/managers","title":"管理器","url":"/zh-hans/4.1/topics/db/managers/"},"formats":{"html":"/zh-hans/4.1/topics/db/search/","markdown":"/zh-hans/4.1/topics/db/search.md","json":"/zh-hans/4.1/topics/db/search.json"},"source":"https://github.com/django/django/blob/stable/4.1.x/docs/topics/db/search.txt","official":"https://docs.djangoproject.com/zh-hans/4.1/topics/db/search/","inVersions":["6.1","6.0","5.2","5.1","5.0","4.2","4.1","4.0","3.2","3.1","3.0","2.2","2.1","2.0"],"inLocales":["en","zh-hans","fr","ja","id","it","pt-br","ko","es","el","pl"]}