123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270 |
- .. _wagtailsearch_searching:
- =========
- Searching
- =========
- .. _wagtailsearch_searching_pages:
- Searching QuerySets
- ===================
- Wagtail search is built on Django's `QuerySet API <https://docs.djangoproject.com/en/1.8/ref/models/querysets/>`_. You should be able to search any Django QuerySet provided the model and the fields being filtered on have been added to the search index.
- Searching Pages
- ---------------
- Wagtail provides a shortcut for searching pages: the ``.search()`` ``QuerySet`` method. You can call this on any ``PageQuerySet``. For example:
- .. code-block:: python
- # Search future EventPages
- >>> from wagtail.wagtailcore.models import EventPage
- >>> EventPage.objects.filter(date__gt=timezone.now()).search("Hello world!")
- All other methods of ``PageQuerySet`` can be used with ``search()``. For example:
- .. code-block:: python
- # Search all live EventPages that are under the events index
- >>> EventPage.objects.live().descendant_of(events_index).search("Event")
- [<EventPage: Event 1>, <EventPage: Event 2>]
- .. note::
- The ``search()`` method will convert your ``QuerySet`` into an instance of one of Wagtail's ``SearchResults`` classes (depending on backend). This means that you must perform filtering before calling ``search()``.
- .. _wagtailsearch_images_documents_custom_models:
- Searching Images, Documents and custom models
- ---------------------------------------------
- Wagtail's document and image models provide a ``search`` method on their QuerySets, just as pages do:
- .. code-block:: python
- >>> from wagtail.wagtailimages.models import Image
- >>> Image.objects.filter(uploaded_by_user=user).search("Hello")
- [<Image: Hello>, <Image: Hello world!>]
- :ref:`Custom models <wagtailsearch_indexing_models>` can be searched by using the ``search`` method on the search backend directly:
- .. code-block:: python
- >>> from myapp.models import Book
- >>> from wagtail.wagtailsearch.backends import get_search_backend
- # Search books
- >>> s = get_search_backend()
- >>> s.search("Great", Book)
- [<Book: Great Expectations>, <Book: The Great Gatsby>]
- You can also pass a QuerySet into the ``search`` method which allows you to add filters to your search results:
- .. code-block:: python
- >>> from myapp.models import Book
- >>> from wagtail.wagtailsearch.backends import get_search_backend
- # Search books
- >>> s = get_search_backend()
- >>> s.search("Great", Book.objects.filter(published_date__year__lt=1900))
- [<Book: Great Expectations>]
- .. _wagtailsearch_specifying_fields:
- Specifying the fields to search
- -------------------------------
- By default, Wagtail will search all fields that have been indexed using ``index.SearchField``.
- This can be limited to a certian set of fields by using the ``fields`` keyword argument:
- .. code-block:: python
- # Search just the title field
- >>> EventPage.objects.search("Event", fields=["title"])
- [<EventPage: Event 1>, <EventPage: Event 2>]
- Changing search behaviour
- -------------------------
- Search operator
- ^^^^^^^^^^^^^^^
- The search operator specifies how search should behave when the user has typed in multiple search terms. There are two possible values:
- - "or" - The results must match at least one term (default for Elasticsearch)
- - "and" - The results must match all terms (default for database search)
- Both operators have benefits and drawbacks. The "or" operator will return many more results but will likely contain a lot of results that aren't relevent. The "and" operator only returns results that contain all search terms, but require the user to be more precise with their query.
- We recommend using the "or" operator when ordering by relevance and the "and" operator when ordering by anything else (note: the database backend doesn't currently support ordering by relevance).
- Here's an example of using the ``operator`` keyword argument:
- .. code-block:: python
- # The database contains a "Thing" model with the following items:
- # - Hello world
- # - Hello
- # - World
- # Search with the "or" operator
- >>> s = get_search_backend()
- >>> s.search("Hello world", Things, operator="or")
- # All records returned as they all contain either "hello" or "world"
- [<Thing: Hello World>, <Thing: Hello>, <Thing: World>]
- # Search with the "and" operator
- >>> s = get_search_backend()
- >>> s.search("Hello world", Things, operator="and")
- # Only "hello world" returned as that's the only item that contains both terms
- [<Thing: Hello world>]
- For page, image and document models, the ``operator`` keyword argument is also supported on the QuerySet's ``search`` method:
- .. code-block:: python
- >>> Page.objects.search("Hello world", operator="or")
- # All pages containing either "hello" or "world" are returned
- [<Page: Hello World>, <Page: Hello>, <Page: World>]
- Custom ordering
- ^^^^^^^^^^^^^^^
- By default, search results are ordered by relevance, if the backend supports it. To preserve the QuerySet's existing ordering, the ``order_by_relevance`` keyword argument needs to be set to ``False`` on the ``search()`` method.
- For example:
- .. code-block:: python
- # Get a list of events ordered by date
- >>> EventPage.objects.order_by('date').search("Event", order_by_relevance=False)
- # Events ordered by date
- [<EventPage: Easter>, <EventPage: Halloween>, <EventPage: Christmas>]
- .. _wagtailsearch_annotating_results_with_score:
- Annotating results with score
- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- For each matched result, Elasticsearch calculates a "score", which is a number
- that represents how relevant the result is based on the user's query. The
- results are usually ordered based on the score.
- There are some cases where having access to the score is useful (such as
- programmatically combining two queries for different models). You can add the
- score to each result by calling the ``.annotate_score(field)`` method on the
- ``SearchQuerySet``.
- For example:
- .. code-block:: python
- >>> events = EventPage.objects.search("Event").annotate_score("_score")
- >>> for event in events:
- ... print(event.title, event._score)
- ...
- ("Easter", 2.5),
- ("Haloween", 1.7),
- ("Christmas", 1.5),
- Note that the score itself is arbitrary and it is only useful for comparison
- of results for the same query.
- .. _wagtailsearch_frontend_views:
- An example page search view
- ===========================
- Here's an example Django view that could be used to add a "search" page to your site:
- .. code-block:: python
- # views.py
- from django.shortcuts import render
- from wagtail.wagtailcore.models import Page
- from wagtail.wagtailsearch.models import Query
- def search(request):
- # Search
- search_query = request.GET.get('query', None)
- if search_query:
- search_results = Page.objects.live().search(search_query)
- # Log the query so Wagtail can suggest promoted results
- Query.get(search_query).add_hit()
- else:
- search_results = Page.objects.none()
- # Render template
- return render(request, 'search_results.html', {
- 'search_query': search_query,
- 'search_results': search_results,
- })
- And here's a template to go with it:
- .. code-block:: html
- {% extends "base.html" %}
- {% load wagtailcore_tags %}
- {% block title %}Search{% endblock %}
- {% block content %}
- <form action="{% url 'search' %}" method="get">
- <input type="text" name="query" value="{{ search_query }}">
- <input type="submit" value="Search">
- </form>
- {% if search_results %}
- <ul>
- {% for result in search_results %}
- <li>
- <h4><a href="{% pageurl result %}">{{ result }}</a></h4>
- {% if result.search_description %}
- {{ result.search_description|safe }}
- {% endif %}
- </li>
- {% endfor %}
- </ul>
- {% elif search_query %}
- No results found
- {% else %}
- Please type something into the search box
- {% endif %}
- {% endblock %}
- Promoted search results
- =======================
- "Promoted search results" allow editors to explicitly link relevant content to search terms, so results pages can contain curated content in addition to results from the search engine.
- This functionality is provided by the :mod:`~wagtail.contrib.wagtailsearchpromotions` contrib module.
|