01 Start with some notes
Use the Note model from the ORM tutorial and create a few records in the admin. A GET parameter is a good fit for read-only search because the resulting URL can be bookmarked.
02 Filter the QuerySet
Add this view to core/views.py. Q combines the two case-insensitive lookups with OR. The ORM handles query parameters; do not build SQL strings from the search input. Limiting results keeps this small example bounded.
from django.db.models import Q
from django.shortcuts import render
from .models import Note
def note_search(request):
query = request.GET.get("q", "").strip()[:200]
notes = Note.objects.order_by("-created_at")
if query:
notes = notes.filter(Q(title__icontains=query) | Q(body__icontains=query))
return render(request, "core/search.html", {"notes": notes[:50], "query": query})03 Create a search template
Save this as core/templates/core/search.html. The submitted search term remains visible, and the empty branch explains when there are no results.
{% extends "core/base.html" %}
{% block content %}
<h1>Search notes</h1>
<form method="get">
<label for="q">Search</label>
<input id="q" name="q" value="{{ query }}">
<button>Search</button>
</form>
{% for note in notes %}
<article><h2>{{ note.title }}</h2><p>{{ note.body }}</p></article>
{% empty %}
<p>No matching notes. Try another word.</p>
{% endfor %}
{% endblock %}04 Wire it up
Import note_search in config/urls.py and add this route. Visit /search/?q=django and try a word that appears only in a note's body. This example searches shared notes; an application with private notes must also filter by the current user's ownership.
path("search/", note_search, name="note_search"),Read the official Django documentation for details and more examples.