""" Search Analytics Models für Performance Tracking """ from django.db import models from django.contrib.auth.models import User from django.utils import timezone class SearchAnalytics(models.Model): """Search Analytics für Performance Tracking""" query = models.CharField(max_length=255) user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True) result_count = models.IntegerField(default=0) ip_address = models.GenericIPAddressField(null=True, blank=True) user_agent = models.TextField(blank=True) created_at = models.DateTimeField(auto_now_add=True) class Meta: ordering = ['-created_at'] verbose_name = 'Search Analytics' verbose_name_plural = 'Search Analytics' def __str__(self): return f"{self.query} - {self.result_count} results" class SearchSuggestion(models.Model): """Search Suggestions für Auto-Complete""" SUGGESTION_TYPE_CHOICES = [ ('product', 'Produkt'), ('auction', 'Auktion'), ('category', 'Kategorie'), ('tag', 'Tag'), ] query = models.CharField(max_length=255) suggestion_type = models.CharField(max_length=20, choices=SUGGESTION_TYPE_CHOICES) suggestion_text = models.CharField(max_length=255) url = models.URLField(blank=True) use_count = models.IntegerField(default=0) is_active = models.BooleanField(default=True) created_at = models.DateTimeField(auto_now_add=True) class Meta: ordering = ['-use_count', 'suggestion_text'] verbose_name = 'Search Suggestion' verbose_name_plural = 'Search Suggestions' unique_together = ['query', 'suggestion_text'] def __str__(self): return f"{self.query} -> {self.suggestion_text}" def increment_use_count(self): """Verwendungszähler erhöhen""" self.use_count += 1 self.save(update_fields=['use_count']) class SearchSynonym(models.Model): """Search Synonyms für bessere Suchergebnisse""" primary_term = models.CharField(max_length=100) synonym_terms = models.TextField(help_text="Komma-getrennte Synonyme") language = models.CharField(max_length=10, default='de') is_active = models.BooleanField(default=True) created_at = models.DateTimeField(auto_now_add=True) class Meta: ordering = ['primary_term'] verbose_name = 'Search Synonym' verbose_name_plural = 'Search Synonyms' unique_together = ['primary_term', 'language'] def __str__(self): return f"{self.primary_term} ({self.language})" def get_synonyms_list(self): """Synonyme als Liste zurückgeben""" return [term.strip() for term in self.synonym_terms.split(',') if term.strip()] class SearchTrend(models.Model): """Search Trends für Analytics""" date = models.DateField() total_searches = models.IntegerField(default=0) unique_users = models.IntegerField(default=0) avg_results = models.FloatField(default=0) popular_queries = models.JSONField(default=list) search_success_rate = models.FloatField(default=0) # % der Suchen mit Ergebnissen class Meta: unique_together = ['date'] verbose_name = 'Search Trend' verbose_name_plural = 'Search Trends' def __str__(self): return f"Search Trends - {self.date}" @classmethod def get_or_create_today(cls): """Heutige Trends erstellen oder abrufen""" today = timezone.now().date() trend, created = cls.objects.get_or_create(date=today) return trend def update_trends(self): """Trends basierend auf Analytics aktualisieren""" from django.db.models import Count, Avg # Get today's analytics today_analytics = SearchAnalytics.objects.filter( created_at__date=self.date ) self.total_searches = today_analytics.count() self.unique_users = today_analytics.values('user').distinct().count() if self.total_searches > 0: self.avg_results = today_analytics.aggregate( avg=Avg('result_count') )['avg'] or 0 # Popular queries popular = today_analytics.values('query').annotate( count=Count('id') ).order_by('-count')[:10] self.popular_queries = [ {'query': item['query'], 'count': item['count']} for item in popular ] # Success rate (searches with results) successful_searches = today_analytics.filter(result_count__gt=0).count() self.search_success_rate = (successful_searches / self.total_searches) * 100 self.save() class SearchIndex(models.Model): """Search Index Status Tracking""" INDEX_STATUS_CHOICES = [ ('building', 'Wird erstellt'), ('updating', 'Wird aktualisiert'), ('ready', 'Bereit'), ('error', 'Fehler'), ] index_name = models.CharField(max_length=100, unique=True) status = models.CharField(max_length=20, choices=INDEX_STATUS_CHOICES, default='ready') last_build = models.DateTimeField(null=True, blank=True) document_count = models.IntegerField(default=0) index_size = models.BigIntegerField(default=0) # in bytes error_message = models.TextField(blank=True) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta: ordering = ['index_name'] verbose_name = 'Search Index' verbose_name_plural = 'Search Indexes' def __str__(self): return f"{self.index_name} - {self.get_status_display()}" @classmethod def get_or_create_index(cls, name): """Index erstellen oder abrufen""" index, created = cls.objects.get_or_create(index_name=name) return index def mark_building(self): """Index als im Aufbau markieren""" self.status = 'building' self.save(update_fields=['status']) def mark_ready(self, document_count=0, index_size=0): """Index als bereit markieren""" self.status = 'ready' self.last_build = timezone.now() self.document_count = document_count self.index_size = index_size self.error_message = '' self.save() def mark_error(self, error_message): """Index als fehlerhaft markieren""" self.status = 'error' self.error_message = error_message self.save(update_fields=['status', 'error_message'])