Filtrage par catégorie et recherche par mot-clé
Dans ce chapitre, vous apprendrez à gérer les paramètres de requête URL, à implémenter une navigation par filtrage de catégorie, et une fonctionnalité de recherche par mot-clé.
Paramètres de requête URL
Les paramètres de requête sont la partie de l'URL après le point d'interrogation, tels que/?category=django&q=入门。
Dans les fonctions de vue Django, utilisezrequest.GETRécupérez ces paramètres.
Exemple
# request.GET est un objet de type dictionnaire
# .get('key', 'Default value') récupère en toute sécurité le paramètre, renvoie la valeur par défaut s'il n'existe pas
category_slug = request.GET.get('category', '') # Filtre de catégorie
keyword = request.GET.get('q', '') # Mots-clés de recherche
print(f'Catégorie : {category_slug}, Recherche : {keyword}')
Filtrage chaîné ORM et objets Q
Le filtrage et la recherche nécessitent d'assembler dynamiquement les conditions de requête.
Exemple
from django.shortcuts import render
from django.db.models import Q # Les objets Q sont utilisés pour combiner des conditions de requête complexes.
from .models import Post, Category
def index(request):
"""Page d'accueil du blog : afficher la liste des articles, prendre en charge le filtrage par catégorie + la recherche par mot-clé"""
posts = Post.objects.all().order_by('-created_at')
# 1. Obtenir les paramètres de requête
category_slug = request.GET.get('category', '')
keyword = request.GET.get('q', '')
# 2. Filtrer par catégorie
if category_slug:
# category__slug : accéder au champ slug de la table des catégories via la clé étrangère (double tiret bas)
posts = posts.filter(category__slug=category_slug)
# 3. Rechercher par mot-clé (titre ou résumé)
if keyword:
# Q(title__icontains=...) | Q(summary__icontains=...): combinaison OU
# icontains : requête contains insensible à la casse
posts = posts.filter(
Q(title__icontains=keyword) | Q(summary__icontains=keyword)
)
# 4. Récupérer toutes les catégories (pour le rendu de la navigation de filtres)
categories = Category.objects.all()
context = {
'posts': posts,
'categories': categories,
'category_slug': category_slug, # Passé au template pour mettre en évidence la sélection actuelle
'keyword': keyword, # Renvoyer les mots-clés de recherche
'title': 'EXAMPLE Blog - Accueil',
}
return render(request, 'blog/index.html', context)
Explication des méthodes de requête ORM
| Méthodes | Signification | Exemple |
|---|---|---|
field__exact | Correspondance exacte | title__exact='Django' |
field__iexact | Correspondance exacte insensible à la casse | title__iexact='django' |
field__contains | Contient (sensible à la casse) | title__contains='入门' |
field__icontains | Contient (insensible à la casse) | title__icontains='django' |
field__gte / lte | Supérieur ou égal à / Inférieur ou égal à | created_at__gte='2024-01-01' |
field__in=[...] | Dans la liste | category__in=[1, 2, 3] |
Double underscore
__est une convention fondamentale de l'ORM Django : utilisée pour accéder aux champs des modèles associés, ou pour spécifier comment interroger les champs. Par exemplecategory__slugreprésente la traversée de la clé étrangère vers le champ slug de la table Category.
Mettre à jour le template de la page d'accueil
Ajouter une navigation de filtrage par catégorie et une zone de recherche au-dessus de la liste des articles.
Exemple
{% extends 'blog/base.html' %}
{% block title %}{{ title }}{% endblock %}
{% block content %}
<h2 class="section-title">Derniers articles</h2>
<!-- Boîte de recherche -->
<div class="search-bar">
<!-- Formulaire method="get":les paramètres soumis apparaissent dans l'URL(/search/?q=xxx) -->
<form method="get" action="{% url 'index' %}">
<input
type="text"
name="q"
value="{{ keyword }}"
placeholder="Rechercher des titres ou des résumés d'articles..."
class="search-input"
/>
{% if keyword %}
<a href="{% url 'index' %}" class="clear-btn">✕</a>
{% endif %}
</forme>
</div>
<!-- Navigation de filtrage par catégorie -->
<div class="category-bar">
<!-- Bouton « Toutes » : sans paramètre de catégorie -->
<a href="{% url 'index' %}"
class="{% if not category_slug %}active{% endif %}">Toutes</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>
<!-- Statistiques des résultats de filtrage -->
<p class="result-info">
Total {{ posts.count }} articles
{% if keyword %}, recherche de "{{ 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">Aucun article correspondant trouvé</p>
{% endif %}
{% endblock %}
Styles de navigation de filtre et de champ de recherche
Exemple
.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;
}
Les liens des boutons de catégorie conservent également
categoryetkeywordParamètres :?category={{ cat.slug }}&q={{ keyword }}. Ainsi, après qu'un utilisateur a d'abord effectué une recherche puis cliqué sur une catégorie, la condition de recherche n'est pas perdue, et les deux conditions prennent effet simultanément.
Mise en pratique : tester le filtrage et la recherche
Démarrez le serveur et vérifiez les points suivants :
- Cliquez sur le bouton de catégorie pour afficher uniquement les articles de la catégorie correspondante.
- Saisissez des mots-clés pour filtrer les titres et les résumés en temps réel.
- Catégorie + recherche : les résultats filtrés satisfont les deux conditions simultanément
- Le bouton "Tous" efface le filtre de catégorie et rétablit l'affichage de tous les articles.
Résumé du chapitre
Dans ce chapitre, vous avez maîtrisé les méthodes de gestion des paramètres de requête URL dans Django : utiliser request.GET.get() pour obtenir des paramètres, le filtrage en chaîne ORM + les objets Q pour implémenter des requêtes complexes, et concaténer dynamiquement les paramètres URL dans les templates pour implémenter des liens de filtre.
Le filtrage par catégorie et la fonctionnalité de recherche permettent aux utilisateurs de trouver rapidement des articles qui les intéressent.
autres extensions