Adding basic search to your Django site
While most people probably find content on your site through Google, it might still be a good idea to just add a basic search functionality to it. You can control which fields to search, how your results are displayed, and your readers won't have to leave your site. You may also have content that is not yet public that you want to be able to search, such as unpublished articles or blog posts.
For this blog, I just used the generic ListView and basic query filtering.
Here's an example:
# templates/base.html ... <form id="searchform" action="{% url 'blog_search_list_view' %}" method="get" accept-charset="utf-8"> <button class="searchbutton" type="submit"> <i class="fa fa-search"></i> </button> <input class="searchfield" id="searchbox" name="q" type="text" placeholder="Search"> </form> ...
# blogs/views.py import operator from django.db.models import Q class BlogSearchListView(BlogListView): """ Display a Blog List page filtered by the search query. """ paginate_by = 10 def get_queryset(self): result = super(BlogSearchListView, self).get_queryset() query = self.request.GET.get('q') if query: query_list = query.split() result = result.filter( reduce(operator.and_, (Q(title__icontains=q) for q in query_list)) | reduce(operator.and_, (Q(content__icontains=q) for q in query_list)) ) return result
So in my search form, I'm just passing in the query value to my search view using the 'q' parameter. Then in my view, I search the 'title' and 'content' fields.
To make the search a little smarter, say someone searches for 'container docker ansible' and I want to search the records where all 3 words appear in the blog content in any order, I split the query into separate words and chain them.
For example, in this code fragment:
query_list = query.split() result.filter( reduce(operator.and_, (Q(content__icontains=q) for q in query_list)) )
The filter part basically does an SQL query similar to this:
SELECT * FROM blog_table WHERE content LIKE '%first_word%' AND content LIKE '%second_word%' AND content LIKE '%third_word%'
This is good and fast enough for my blog. I can probably have a few thousand posts and it will still be fast enough even without indexing.
Update: If you're using Django 1.10 or higher with PostgreSQL, check out this new post about full-text search.
Tags: howto, django, tech, software development, search