Wagtail Tutorials #7: Add Search Function In Wagtail Blog

Last updated on Jan 20 2019 by Michael Yin

Introduction

In this Wagtail tutorial, I will talk about how to implement search function in Wagtail blog so the user can search the posts through keywords.

Basic search function

Wagtail search can work with many backend systems such as Database, ElasticSearch and Whoosh, considering what we build is a blog application, I will use database backend here because Elasticsearch is too heavy for us.

First, we continue to add a new route to our BlogPage, to make it can handle search path in URL.

class BlogPage(RoutablePageMixin, Page):
    @route(r'^search/$')
    def post_search(self, request, *args, **kwargs):
        search_query = request.GET.get('q', None)
        self.posts = self.get_posts()
        if search_query:
            self.posts = self.posts.filter(body__contains=search_query)
            self.search_term = search_query
            self.search_type = 'search'
        return Page.serve(self, request, *args, **kwargs)

The method above is a view function handle the search request, we use filter method in Django ORM to filter the posts by search keywords. body__contains means to find posts, body of which contains the keywords, the query would be translated to SQL like this SELECT ... WHERE body LIKE '%search_query%';.

If you read above code carefully, you will notice that there is search_term and search_type here, which I will talk about in a bit.

Add search form to template

Now we need to add search form in our sidebar.html so use can enter the keyword in this form.

<form role="search" method="get" class="form-search" action="{% routablepageurl blog_page "post_search" %}" method="get">
    <div class="input-group">
        <input type="text" class="form-control search-query" name="q" placeholder="Search&hellip;" title="Search for:" />
        <span class="input-group-btn">
          <button type="submit" class="btn btn-default" name="submit" id="searchsubmit" value="Search">
            <span class="glyphicon glyphicon-search"></span>
          </button>
        </span>
    </div>
</form>

We use routablepageurl to resolve the search url for us, which has been explained in the previous tutorial, keyword will be sent through HTTP GET method, which can be found in http parameters with key q.

To make users can see what they are searching, we need to show the keywords in the template, that is why search_query and search_type has been used to tell us the search type (search, tag, category) and search keyword (keyword, category name, tag name).

We can add this to the top of the blog_page.html

{% if search_term %}
  <header class="page-header">
      <h1 class="page-title">Search Results for <span>{{ search_type }}: {{ search_term }}</span></h1>
  </header>
{% endif %}
......

Here is the screenshot of our Wagtail Blog.

How to search multiple fields at one time?

You can set search_fields to make user search multiple fields at once.

search_fields = Page.search_fields + [
    index.SearchField('title'),
    index.SearchField('body'),
]

Then please use self.posts.search(search_query) to do full-text search.

Some notes about search backend in Wagtail

Some people have no idea what backend they should use in wagtail project to support search I must say that depends on the data you want to index, if the data is big and you want the results to be more accurate, you should use big and heavy framework such as ElasticSearch, but based on my experience, most users have no need to import this tool. Remember to check the hardware before choosing ElasticSearch.

For most CMS projects, Postgres backend is a very good option for the following reasons.

  1. Postgres is a relation DB and Django can work with it very well.
  2. Postgres has full-text search support, and Wagtail has Postgres backend which supports full-text search feature very well.

If you are using SQLite db and you care about the performance of SQL Like. You can take a look at wagtail-whoosh.

If you are also using Haystack

If you have used Haystack in your project to support other custom search function, then I am sure you have met strange problem which told you All documents removed. Updating backend: default: Backend doesn't require rebuild. Skipping after importing Wagtail to your project.

The reason why this happens is the command name conflict, update_index exists in both frameworks, so Django can not determine which command should be called each time. So how to make both framework coexist in one project, you can find the solution and discussion here.

Updated in Jan, 4, 2019:

Haystack support Whoosh, Solr and Elascicsearch. Since Wagtail support Whoosh and Elasticsearch now, you can stop using haystack in your project.

As for Solr, you can let Postgres db to handle similar jobs, if you need more detail or tips about this, just contact me.

Conclusion

In this Wagtail tutorial, I showed you how to implement search function in wagtail blog so user can find the posts through the keywords, and give you some tips about search function in Wagtail.

The source code of this Wagtail tutorial is available on Github, you can get it here wagtail-bootstrap-blog, and I would appreciate that if you could star my repo.

You can also check the full list of my wagtail tutorial here wagtail tutorial series

I'm a passionate Python developer from China and love writing code, articles about Django and Wagtail CMS.

Michael Yin

Founder of AccordBox

Need any Help in your Project?

Sign up to our newsletter