File size: 4,845 Bytes
fafd0bb |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
# ============================================
# apps/analytics/services.py - Search Tracking Service
# ============================================
from apps.analytics.models import SearchLog, PopularSearch
from django.db.models import F
class SearchTrackingService:
"""Service centralisé pour tracker les recherches"""
@staticmethod
def log_search(
category: str,
search_query: str,
user=None,
filters_applied: dict = None,
results_count: int = 0,
request=None
):
"""
Enregistre une recherche dans les logs
Args:
category: Catégorie de recherche (QUESTIONS, MENTORS, etc.)
search_query: Terme recherché
user: Utilisateur qui effectue la recherche (None si anonyme)
filters_applied: Dict des filtres appliqués
results_count: Nombre de résultats retournés
request: Objet request Django pour extraire métadonnées
Returns:
SearchLog instance
"""
# Extraire métadonnées de la requête si disponible
session_id = ''
ip_address = None
user_agent = ''
page_url = ''
if request:
session_id = request.session.session_key or ''
ip_address = request.META.get('REMOTE_ADDR')
user_agent = request.META.get('HTTP_USER_AGENT', '')[:500]
page_url = request.META.get('HTTP_REFERER', '')[:500]
# Créer le log
search_log = SearchLog.objects.create(
user=user,
category=category,
search_query=search_query.strip()[:500],
filters_applied=filters_applied or {},
results_count=results_count,
session_id=session_id,
ip_address=ip_address,
user_agent=user_agent,
page_url=page_url
)
# Mettre à jour les recherches populaires
SearchTrackingService._update_popular_search(category, search_query.strip())
return search_log
@staticmethod
def _update_popular_search(category: str, search_query: str):
"""Mise à jour incrémentale des recherches populaires"""
if not search_query or len(search_query) < 2:
return
popular, created = PopularSearch.objects.get_or_create(
category=category,
search_query=search_query[:500],
defaults={'search_count': 1}
)
if not created:
popular.search_count = F('search_count') + 1
popular.save(update_fields=['search_count', 'last_searched'])
@staticmethod
def log_result_click(search_log_id: int, result_id: str, position: int):
"""
Enregistre le clic sur un résultat de recherche
Args:
search_log_id: ID du SearchLog
result_id: ID du résultat cliqué
position: Position dans la liste (0-indexed)
"""
try:
search_log = SearchLog.objects.get(id=search_log_id)
search_log.clicked_result_id = str(result_id)
search_log.clicked_result_position = position
search_log.save(update_fields=['clicked_result_id', 'clicked_result_position'])
except SearchLog.DoesNotExist:
pass
@staticmethod
def get_popular_searches(category: str = None, limit: int = 10):
"""
Récupère les recherches les plus populaires
Args:
category: Filtrer par catégorie (None = toutes)
limit: Nombre max de résultats
Returns:
QuerySet de PopularSearch
"""
qs = PopularSearch.objects.all()
if category:
qs = qs.filter(category=category)
return qs[:limit]
@staticmethod
def get_trending_searches(category: str = None, days: int = 7, limit: int = 10):
"""
Récupère les recherches tendances (populaires récemment)
Args:
category: Filtrer par catégorie
days: Nombre de jours à considérer
limit: Nombre max de résultats
Returns:
Liste de dicts avec query et count
"""
from django.utils import timezone
from datetime import timedelta
from django.db.models import Count
since = timezone.now() - timedelta(days=days)
qs = SearchLog.objects.filter(created_at__gte=since)
if category:
qs = qs.filter(category=category)
trending = qs.values('search_query').annotate(
count=Count('id')
).order_by('-count')[:limit]
return list(trending)
|