Django2.0手册:Search

A common task for web applications is to search some data in the database with
user input. In a simple case, this could be filtering a list of objects by a
category. A more complex use case might require searching with weighting,
categorization, highlighting, multiple languages, and so on. This document
explains some of the possible use cases and the tools you can use.

We’ll refer to the same models used in Making queries.

Use Cases¶

Standard textual queries¶

Text-based fields have a selection of simple matching operations. For example,
you may wish to allow lookup up an author like so:

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

This is a very fragile solution as it requires the user to know an exact
substring of the author’s name. A better approach could be a case-insensitive
match (icontains), but this is only marginally better.

A database’s more advanced comparison functions¶

If you’re using PostgreSQL, Django provides a selection of database
specific tools
to allow you to leverage more
complex querying options. Other databases have different selections of tools,
possibly via plugins or user-defined functions. Django doesn’t include any
support for them at this time. We’ll use some examples from PostgreSQL to
demonstrate the kind of functionality databases may have.

Searching in other databases

All of the searching tools provided by django.contrib.postgres are
constructed entirely on public APIs such as custom lookups and database functions. Depending on your database, you should
be able to construct queries to allow similar APIs. If there are specific
things which cannot be achieved this way, please open a ticket.

In the above example, we determined that a case insensitive lookup would be
more useful. When dealing with non-English names, a further improvement is to
use unaccented comparison:

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

This shows another issue, where we are matching against a different spelling of
the name. In this case we have an asymmetry though – a search for Helen
will pick up Helena or Hélène, but not the reverse. Another option
would be to use a trigram_similar comparison, which compares
sequences of letters.

例如:

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

Now we have a different problem – the longer name of “Helena Bonham Carter”
doesn’t show up as it is much longer. Trigram searches consider all
combinations of three letters, and compares how many appear in both search and
source strings. For the longer name, there are more combinations which appear
in the source string so it is no longer considered a close match.

The correct choice of comparison functions here depends on your particular data
set, for example the language(s) used and the type of text being searched. All
of the examples we’ve seen are on short strings where the user is likely to
enter something close (by varying definitions) to the source data.