Category filtering and keyword search
In this chapter, you will learn to handle URL query parameters, implement category filtering navigation, and keyword search functionality.
URL query parameters
Query parameters are the part of the URL after the question mark, such as/?category=django&q=入门。
In Django view functions, userequest.GETGet these parameters.
Example
# request.GET is a dictionary-like object
# .get('key', 'Default value') safely get parameter, return default if it does not exist
category_slug = request.GET.get('category', '') # Category filter
keyword = request.GET.get('q', '') # Search Keywords
print(f'Category: {category_slug}, Search: {keyword}')
ORM chained filtering and Q objects
Filtering and searching require dynamically assembling query conditions.
Example
from django.shortcuts import render
from django.db.models import Q # Q objects are used to combine complex query conditions.
from .models import Post, Category
def index(request):
"""Blog home page: display article list, support category filtering + keyword search"""
posts = Post.objects.all().order_by('-created_at')
# 1. Get query parameters
category_slug = request.GET.get('category', '')
keyword = request.GET.get('q', '')
# 2. Filter by category
if category_slug:
# category__slug: access the slug field of the category table through the foreign key (double underscore)
posts = posts.filter(category__slug=category_slug)
# 3. Search by keyword (title or summary)
if keyword:
# Q(title__icontains=...) | Q(summary__icontains=...): OR combination
# icontains: case-insensitive contains query
posts = posts.filter(
Q(title__icontains=keyword) | Q(summary__icontains=keyword)
)
# 4. Get all categories (for rendering filter navigation)
categories = Category.objects.all()
context = {
'posts': posts,
'categories': categories,
'category_slug': category_slug, # Passed to the template to highlight the current selection
'keyword': keyword, # Echo search keywords
'title': 'EXAMPLE Blog - Home',
}
return render(request, 'blog/index.html', context)
Explanation of ORM query methods
| Methods | Meaning | Example |
|---|---|---|
field__exact | Exact match | title__exact='Django' |
field__iexact | Case-insensitive exact match | title__iexact='django' |
field__contains | Contains (case-sensitive) | title__contains='入门' |
field__icontains | Contains (case-insensitive) | title__icontains='django' |
field__gte / lte | Greater than or equal to / Less than or equal to | created_at__gte='2024-01-01' |
field__in=[...] | In the list | category__in=[1, 2, 3] |
Double underscore
__is a core convention of Django ORM: used to access fields of related models, or specify how to query fields. For examplecategory__slugrepresents crossing the foreign key to the slug field of the Category table.
Update the homepage template
Add category filtering navigation and a search box above the article list.
Example
{% extends 'blog/base.html' %}
{% block title %}{{ title }}{% endblock %}
{% block content %}
<h2 class="section-title">Latest Articles</h2>
<!-- Search box -->
<div class="search-bar">
<!-- Table单 method="get":SubmitafterParameterappears in In the URL(/search/?q=xxx) -->
<form method="get" action="{% url 'index' %}">
<input
type="text"
name="q"
value="{{ keyword }}"
placeholder=Search article titles or summaries...
class="search-input"
/>
{% if keyword %}
<a href="{% url 'index' %}" class="clear-btn">✕</a>
{% endif %}
</form>
</div>
<!-- Category filter navigation -->
<div class="category-bar">
<!-- 'All' button: without category parameter -->
<a href="{% url 'index' %}"
class="{% if not category_slug %}active{% endif %}">All</a>
{% for cat in categories %}
<a href="{% url 'index' %}?category={{ cat.slug }}{% if keyword %}&q={{ keyword }}{% endif %}"
class="{% if category_slug == cat.slug %}active{% endif %}">
{{ cat.name }}
</a>
{% endfor %}
</div>
<!-- Filter result statistics -->
<p class="result-info">
Total {{ posts.count }} posts
{% if keyword %}, searching "{{ keyword }}"{% endif %}
</p>
{% if posts %}
<div class="article-grid">
{% for post in posts %}
<a href="{% url 'post_detail' post.pk %}" class="card-link">
<div class="article-card">
<div class="card-content">
<span class="card-category">{{ post.category.name }}</span>
<h3>{{ post.title }}</h3>
<p>{{ post.summary|truncatechars:80 }}</p>
<span class="card-date">{{ post.created_at|date:"Y-m-d" }}</span>
</div>
</div>
</a>
{% endfor %}
</div>
{% else %}
<p class="empty-tip">No matching articles found</p>
{% endif %}
{% endblock %}
Filter navigation and search box styles
Example
.search-bar {
margin-bottom: 20px;
}
.search-input {
width: 100%;
padding: 12px 16px;
border: 2px solid #eee;
border-radius: 8px;
font-size: 15px;
outline: none;
transition: border-color 0.2s;
}
.search-input:focus {
border-color: #2c3e50;
}
.clear-btn {
position: absolute;
right: 12px;
top: 50%;
transform: translateY(-50%);
color: #999;
text-decoration: none;
font-size: 18px;
}
.category-bar {
display: flex;
gap: 10px;
margin-bottom: 16px;
flex-wrap: wrap;
}
.category-bar a {
padding: 6px 16px;
border: 1px solid #ddd;
border-radius: 20px;
text-decoration: none;
color: #333;
font-size: 14px;
transition: all 0.2s;
}
.category-bar a.active {
background: #2c3e50;
color: #fff;
border-color: #2c3e50;
}
.category-bar a:hover {
border-color: #2c3e50;
}
.result-info {
color: #999;
font-size: 14px;
margin-bottom: 16px;
}
.card-link {
text-decoration: none;
color: inherit;
}
The category button links also retain
categoryandkeywordParameters:?category={{ cat.slug }}&q={{ keyword }}. This way, after users search first and then click a category, the search condition is not lost, and both conditions take effect simultaneously.
Hands-on: Test filtering and search
Start the server and verify the following points:
- Click the category button to display only articles of the corresponding category.
- Enter keywords to filter titles and summaries in real time.
- Category + search stacking: filtered results satisfy both conditions simultaneously
- The "All" button clears the category filter and restores display of all articles.
Chapter summary
In this chapter, you mastered the methods of handling URL query parameters in Django: using request.GET.get() to obtain parameters, ORM chained filtering + Q objects to implement complex queries, and dynamically concatenating URL parameters in templates to implement filter links.
Category filtering and search functionality allow users to quickly find articles of interest.
other extensions