|
|
|
|
|
|
|
|
|
|
|
from django.db import models |
|
|
from apps.core.models import TimestampMixin |
|
|
from apps.users.models import User |
|
|
|
|
|
class SearchLog(TimestampMixin): |
|
|
""" |
|
|
Enregistre chaque recherche effectuée sur la plateforme |
|
|
pour analyser les intérêts et comportements des utilisateurs |
|
|
""" |
|
|
CATEGORY_CHOICES = [ |
|
|
('QUESTIONS', 'Questions du Forum'), |
|
|
('MENTORS', 'Recherche de Mentors'), |
|
|
('OPPORTUNITIES', 'Opportunités'), |
|
|
('TOOLS', 'Outils Pédagogiques'), |
|
|
('USERS', 'Utilisateurs'), |
|
|
('GENERAL', 'Recherche Générale'), |
|
|
] |
|
|
|
|
|
|
|
|
user = models.ForeignKey( |
|
|
User, |
|
|
on_delete=models.SET_NULL, |
|
|
null=True, |
|
|
blank=True, |
|
|
related_name='search_logs', |
|
|
help_text="Utilisateur qui a effectué la recherche (null si anonyme)" |
|
|
) |
|
|
|
|
|
|
|
|
category = models.CharField( |
|
|
max_length=20, |
|
|
choices=CATEGORY_CHOICES, |
|
|
db_index=True, |
|
|
help_text="Type de contenu recherché" |
|
|
) |
|
|
|
|
|
|
|
|
search_query = models.CharField( |
|
|
max_length=500, |
|
|
db_index=True, |
|
|
help_text="Texte saisi par l'utilisateur" |
|
|
) |
|
|
|
|
|
|
|
|
filters_applied = models.JSONField( |
|
|
default=dict, |
|
|
blank=True, |
|
|
help_text="Filtres appliqués lors de la recherche (ex: {\"status\": \"solved\", \"tags\": [\"math\"]})" |
|
|
) |
|
|
|
|
|
|
|
|
results_count = models.IntegerField( |
|
|
default=0, |
|
|
help_text="Nombre de résultats retournés" |
|
|
) |
|
|
|
|
|
|
|
|
session_id = models.CharField( |
|
|
max_length=100, |
|
|
blank=True, |
|
|
db_index=True, |
|
|
help_text="ID de session pour regrouper les recherches d'une même visite" |
|
|
) |
|
|
|
|
|
ip_address = models.GenericIPAddressField( |
|
|
null=True, |
|
|
blank=True, |
|
|
help_text="Adresse IP de l'utilisateur" |
|
|
) |
|
|
|
|
|
user_agent = models.TextField( |
|
|
blank=True, |
|
|
help_text="User agent du navigateur" |
|
|
) |
|
|
|
|
|
|
|
|
page_url = models.CharField( |
|
|
max_length=500, |
|
|
blank=True, |
|
|
help_text="URL de la page où la recherche a été effectuée" |
|
|
) |
|
|
|
|
|
|
|
|
clicked_result_id = models.CharField( |
|
|
max_length=100, |
|
|
null=True, |
|
|
blank=True, |
|
|
help_text="ID du résultat cliqué (si applicable)" |
|
|
) |
|
|
|
|
|
clicked_result_position = models.IntegerField( |
|
|
null=True, |
|
|
blank=True, |
|
|
help_text="Position du résultat cliqué dans la liste" |
|
|
) |
|
|
|
|
|
class Meta: |
|
|
db_table = 'search_logs' |
|
|
verbose_name = 'Recherche' |
|
|
verbose_name_plural = 'Recherches' |
|
|
indexes = [ |
|
|
models.Index(fields=['category', '-created_at']), |
|
|
models.Index(fields=['user', '-created_at']), |
|
|
models.Index(fields=['search_query']), |
|
|
models.Index(fields=['-created_at']), |
|
|
] |
|
|
ordering = ['-created_at'] |
|
|
|
|
|
def __str__(self): |
|
|
user_info = self.user.email if self.user else "Anonyme" |
|
|
return f"{user_info} - {self.category}: '{self.search_query}'" |
|
|
|
|
|
|
|
|
class PopularSearch(models.Model): |
|
|
""" |
|
|
Vue matérialisée des recherches les plus populaires |
|
|
Mise à jour périodiquement pour optimiser les performances |
|
|
""" |
|
|
category = models.CharField(max_length=20, choices=SearchLog.CATEGORY_CHOICES) |
|
|
search_query = models.CharField(max_length=500) |
|
|
search_count = models.IntegerField(default=0) |
|
|
last_searched = models.DateTimeField(auto_now=True) |
|
|
|
|
|
class Meta: |
|
|
db_table = 'popular_searches' |
|
|
verbose_name = 'Recherche Populaire' |
|
|
verbose_name_plural = 'Recherches Populaires' |
|
|
unique_together = ['category', 'search_query'] |
|
|
ordering = ['-search_count', '-last_searched'] |
|
|
|
|
|
def __str__(self): |
|
|
return f"{self.category}: '{self.search_query}' ({self.search_count}x)" |
|
|
|