Фильтрация по категориям и поиск по ключевым словам
В этой главе вы научитесь обрабатывать параметры URL-запроса, реализовывать навигацию с фильтрацией по категориям и функциональность поиска по ключевым словам.
Параметры URL-запроса
Параметры запроса — это часть URL после вопросительного знака, например/?category=django&q=入门。
В функциях представления Django используйтеrequest.GETПолучите эти параметры.
Пример
# request.GET — объект, подобный словарю
# .get('key', 'Default value') безопасно получает параметр и возвращает значение по умолчанию, если он не существует
category_slug = request.GET.get('category', '') # Фильтр по категории
keyword = request.GET.get('q', '') # Ключевые слова для поиска
print(f'Category: {category_slug}, Search: {keyword}')
Цепочная фильтрация ORM и Q-объекты
Фильтрация и поиск требуют динамического формирования условий запроса.
Пример
from django.shortcuts import render
from django.db.models import Q # Q-объекты используются для объединения сложных условий запроса.
from .models import Post, Category
def index(request):
"""Главная страница блога: отображение списка статей, поддержка фильтрации по категориям + поиска по ключевым словам"""
posts = Post.objects.all().order_by('-created_at')
# 1. Получить параметры запроса
category_slug = request.GET.get('category', '')
keyword = request.GET.get('q', '')
# 2. Фильтрация по категории
if category_slug:
# category__slug: доступ к полю slug таблицы категорий через внешний ключ (двойное подчёркивание)
posts = posts.filter(category__slug=category_slug)
# 3. Поиск по ключевому слову (заголовок или краткое содержание)
if keyword:
# Q(title__icontains=...) | Q(summary__icontains=...): комбинация OR
# icontains: запрос на вхождение без учёта регистра
posts = posts.filter(
Q(title__icontains=keyword) | Q(summary__icontains=keyword)
)
# 4. Получить все категории (для отображения навигации фильтра)
categories = Category.objects.all()
context = {
'posts': posts,
'categories': categories,
'category_slug': category_slug, # Передаётся в шаблон для подсветки текущего выбора
'keyword': keyword, # Вывести поисковые ключевые слова
'title': 'EXAMPLE Blog - Главная',
}
return render(request, 'blog/index.html', context)
Объяснение методов запросов ORM
| Методы | Значение | Пример |
|---|---|---|
field__exact | Точное совпадение | title__exact='Django' |
field__iexact | Точное совпадение без учёта регистра | title__iexact='django' |
field__contains | Содержит (с учётом регистра) | title__contains='入门' |
field__icontains | Содержит (без учёта регистра) | title__icontains='django' |
field__gte / lte | Больше или равно / Меньше или равно | created_at__gte='2024-01-01' |
field__in=[...] | В списке | category__in=[1, 2, 3] |
Двойное подчёркивание
__является основным соглашением Django ORM: используется для доступа к полям связанных моделей или указания, как запрашивать поля. Напримерcategory__slugобозначает переход по внешнему ключу к полю slug таблицы Category.
Обновите шаблон главной страницы
Добавьте навигацию с фильтрацией по категориям и поле поиска над списком статей.
Пример
{% extends 'blog/base.html' %}
{% block title %}{{ title }}{% endblock %}
{% block content %}
<h2 class="section-title">Последние статьи</h2>
<!-- Поле поиска -->
<div class="search-bar">
<!-- Форма method="get": после отправки параметр появляется в URL (/search/?q=xxx) -->
<form method="get" action="{% url 'index' %}">
<input
type="text"
name="q"
value="{{ keyword }}"
placeholder=Поиск по заголовкам или описаниям статей...
class="search-input"
/>
{% if keyword %}
<a href="{% url 'index' %}" class="clear-btn">✕</a>
{% endif %}
</форма>
</div>
<!-- Навигация фильтра категорий -->
<div class="category-bar">
<!-- Кнопка 'Все': без параметра категории -->
<a href="{% url 'index' %}"
class="{% if not category_slug %}active{% endif %}">Все</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>
<!-- Статистика результатов фильтра -->
<p class="result-info">
Всего {{ posts.count }} записей
{% if keyword %}, поиск "{{ 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">Подходящих статей не найдено</p>
{% endif %}
{% endblock %}
Стили навигации фильтра и поля поиска
Пример
.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;
}
Ссылки на кнопках категорий также сохраняют
categoryиkeywordПараметры:?category={{ cat.slug }}&q={{ keyword }}. Таким образом, когда пользователи сначала выполняют поиск, а затем нажимают категорию, условие поиска не теряется, и оба условия действуют одновременно.
Практика: тестирование фильтрации и поиска
Запустите сервер и проверьте следующие пункты:
- Нажмите кнопку категории, чтобы отображались только статьи соответствующей категории.
- Введите ключевые слова, чтобы фильтровать заголовки и краткие описания в реальном времени.
- Совмещение категории и поиска: отфильтрованные результаты удовлетворяют обоим условиям одновременно
- Кнопка "Все" сбрасывает фильтр категории и восстанавливает отображение всех статей.
Итоги главы
В этой главе вы освоили методы обработки параметров URL-запроса в Django: использование request.GET.get() для получения параметров, цепочную фильтрацию ORM + объекты Q для реализации сложных запросов и динамическое объединение параметров URL в шаблонах для реализации ссылок фильтрации.
Фильтрация по категориям и функция поиска позволяют пользователям быстро находить интересующие статьи.
Другие расширения