DEV Community

Cover image for Implementing search in Django fbv
Aditya
Aditya

Posted on

Implementing search in Django fbv

So after about 2 years after I am writing this blog post.

What can I do?
I am very lazy...

After procrastinating for 2 years I've decided to finally write a blog post


I assume that you have some basic knowledge of Django requests and responses, like GET and POST request and URL mapping etc.

So, let's get to the point.

For example we have a model called Book

# models.py

from django.db import models

class Book(models.Model):
    """
    A Simple Book Model
    """
    ISBN_HELP_URL = "https://www.isbn- 
    international.org/content/what-isbn"

    name = models.CharField(max_length=255)
    author = models.CharField(max_length=255)
    summary = models.TextField(blank=True, null=True)
    isbn = models.CharField(help_text=f"<a href='{ISBN_HELP_URL}' 
    target='_blank'>More Info</a>", max_length=10)
    genre = models.CharField(max_length=255, help_text="Enter a 
    book genre (e.g. Science Fiction, French Poetry etc.)")

    def __str__(self):
        return self.name

Enter fullscreen mode Exit fullscreen mode

So we want to make a page to search for a Book based on the following fields:

  • name
  • author
  • summary
  • isbn
  • genre

We can simply use the Q operator.
It is built in to Django.
It is used to Join the querysets.

Here is a simple example:

# views.py

from django.db.models import Q
from django.shortcuts import render, redirect
from .models import Book

def frontpage(request):
"""
The default frontpage

Return all the books in the database.
"""
books = Book.objects.all()
   return render(request, "frontpage.html", {"books": books})

def search(request):
    """
    Searches the books based on the query.
    """
    query = request.GET.get("query", None)
    if query:
        books = Book.objects.filter(
                Q(name__icontains=query) |
                Q(author__icontains=query) |
                Q(summary__icontains=query) |
                Q(isbn__icontains=query) |
                Q(genre__icontains=query)
        )
        return render(request, "search.html", {"books": books})

    return redirect(request, "frontpage")
Enter fullscreen mode Exit fullscreen mode

Now that looks so complicated, but it isn't
If you understand what this code is doing you can easily implement in your projects

So let's break this down into pieces.

  1. The function frontpage, well shows the frontpage with all the Books in the database, easy.

  2. The search function searches the books based on the query entered by the user.
    The query can match the name, author, summary, ISBN, or genre of the book.
    If a query is entered, the function filters the books and returns the filtered books to be displayed in the "search.html" template.
    If no query is entered, the function redirects the user to the "frontpage".

We are firstly importing the Q operator from django.db.models.
Then we are filtering the Books based on the fields

This is the main code

books = Book.objects.filter(
                Q(name__icontains=query) |
                Q(author__icontains=query) |
                Q(summary__icontains=query) |
                Q(isbn__icontains=query) |
                Q(genre__icontains=query)
        )
Enter fullscreen mode Exit fullscreen mode

The | indicate that we are joining the queryset so even if the query isn't matched with the name but matched with the author it will fetch that book from the database

This double underscores and icontains represent that we also want to make the query case insensitive.

For example if we want to search for a Book named The Brief History of Time by Stephen Hawking,
We don't have to type the exact name of the book.
The Query could include the following:

  • the brief history of time
  • THE BRIEF HISTORY OF TIME
  • History of Time
  • brief history

The possibilities could get endless.

So now let's map the views to the urls

Open the urls.py

# urls.py

from django.contrib import admin
from django.urls import path
from myapp import views

urlpatterns = [
    path('', views.frontpage, name="frontpage"),
    path('/search/', views.search, name="search"),
    path('admin/', admin.site.urls),
]

Enter fullscreen mode Exit fullscreen mode

Now let's move to the frontend

Create a folder in myapp (Your app folder) named as templates.
In it create two files named:

  • frontpage.html
  • search.html

If you wish you can use a base.html and template inheritance, but here I will be doing the simple html with no css, so it will look ugly.

<!-- frontpage.html -->
<html>
  <head>
    <title>Jamshedpur Library</title
  </head>
  <body>
    <h2>Jamshedpur Library</h2>
    <p>Frontpage</p>
    <form action="{% url 'search' %}" method="GET">
    <input type="search" placeholder="search" name="query">
    <button type="submit">Search 🔍</button>
    </form>
    <ul>
      {% for book in books %}
        <li>{{ book.name }} by {{ book.author }}</li>
      {% endfor %}
    </ul>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

Yup it's a form which will send get request to search view, remember we have added a name attribute in the url patterns

Now let's see the search.html

<!-- search.html -->
<html>
  <head>
    <title>Jamshedpur Library</title
  </head>
  <body>
    <h2>Jamshedpur Library</h2>
    <form action="{% url 'search' %}" method="GET">
    <input type="search" placeholder="search" name="query">
    <button type="submit">Search 🔍</button>
    </form>
    <p>You have searched for: {{ request.GET.query }}</p>
    <p>Results: {{ books.count }}</p>
    <ul>
      {% for book in books %}
        <li>{{ book.name }} by {{ book.author }}</li>
      {% endfor %}
    </ul>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

So here we are displaying the search results with the no. of results just as in any search engine.

BTW I have not implemented the pagination, so the data isn't spliced into smaller chunks

Well that's how you can implement a simple search in your Django project.


Also, the letter Capital G looks like an arrow going in a circle.

Thanks for reading my post.

@foxy4096 out.
Cheers ✌

Top comments (1)

Collapse
 
foxy4096 profile image
Aditya

I am tired.