""" Advanced Search Views mit Elasticsearch """ from django.shortcuts import render from django.http import JsonResponse from django.contrib.auth.decorators import login_required from django.core.paginator import Paginator from django.conf import settings # from haystack.query import SearchQuerySet # from haystack.forms import SearchForm # from haystack.inputs import AutoQuery # from haystack.backends import SQ import json def advanced_search(request): """Advanced Search mit Elasticsearch""" # Search parameters query = request.GET.get('q', '') category = request.GET.get('category', '') fursuit_type = request.GET.get('fursuit_type', '') price_min = request.GET.get('price_min', '') price_max = request.GET.get('price_max', '') featured = request.GET.get('featured', '') sort_by = request.GET.get('sort', '-created_at') # Initialize search sqs = SearchQuerySet() if query: # Fuzzy search with synonyms search_query = query synonyms = settings.SEARCH_SETTINGS.get('SEARCH_SYNONYMS', {}) for synonym_key, synonym_list in synonyms.items(): if query.lower() in synonym_list: search_query = f"{query} {synonym_key}" break sqs = sqs.filter(text=AutoQuery(search_query)) # Apply filters if category: sqs = sqs.filter(category=category) if fursuit_type: sqs = sqs.filter(fursuit_type=fursuit_type) if price_min: sqs = sqs.filter(price__gte=float(price_min)) if price_max: sqs = sqs.filter(price__lte=float(price_max)) if featured == 'true': sqs = sqs.filter(featured=True) # Apply sorting if sort_by == 'price': sqs = sqs.order_by('price') elif sort_by == '-price': sqs = sqs.order_by('-price') elif sort_by == 'title': sqs = sqs.order_by('title') elif sort_by == '-title': sqs = sqs.order_by('-title') else: sqs = sqs.order_by('-created_at') # Pagination page = request.GET.get('page', 1) paginator = Paginator(sqs, settings.SEARCH_SETTINGS.get('SEARCH_RESULTS_PER_PAGE', 20)) page_obj = paginator.get_page(page) # Facets facets = { 'categories': sqs.facet('category').facet_counts()['fields']['category'], 'fursuit_types': sqs.facet('fursuit_type').facet_counts()['fields']['fursuit_type'], 'price_ranges': [ {'range': '0-100', 'count': sqs.filter(price__range=(0, 100)).count()}, {'range': '100-500', 'count': sqs.filter(price__range=(100, 500)).count()}, {'range': '500-1000', 'count': sqs.filter(price__range=(500, 1000)).count()}, {'range': '1000+', 'count': sqs.filter(price__gte=1000).count()}, ] } # Search analytics if settings.SEARCH_SETTINGS.get('ENABLE_SEARCH_ANALYTICS', True): track_search_analytics(request, query, len(sqs)) context = { 'query': query, 'page_obj': page_obj, 'facets': facets, 'filters': { 'category': category, 'fursuit_type': fursuit_type, 'price_min': price_min, 'price_max': price_max, 'featured': featured, 'sort_by': sort_by, }, 'total_results': len(sqs), 'search_highlight': settings.SEARCH_SETTINGS.get('SEARCH_HIGHLIGHT', True), } return render(request, 'search/advanced_search.html', context) def search_suggestions(request): """AJAX Search Suggestions""" query = request.GET.get('q', '') if len(query) < settings.SEARCH_SETTINGS.get('MIN_SUGGESTION_LENGTH', 2): return JsonResponse({'suggestions': []}) # Get suggestions from Elasticsearch sqs = SearchQuerySet() suggestions = sqs.autocomplete(title_auto=query)[:settings.SEARCH_SETTINGS.get('MAX_SUGGESTIONS', 10)] suggestion_list = [] for suggestion in suggestions: suggestion_list.append({ 'title': suggestion.title, 'url': suggestion.url, 'type': suggestion.model_name, }) return JsonResponse({'suggestions': suggestion_list}) def search_analytics(request): """Search Analytics Dashboard (Admin only)""" if not request.user.is_staff: return JsonResponse({'error': 'Zugriff verweigert'}, status=403) # Get search statistics from search.models import SearchAnalytics analytics = SearchAnalytics.objects.all().order_by('-created_at')[:100] # Popular searches popular_searches = SearchAnalytics.objects.values('query').annotate( count=Count('id') ).order_by('-count')[:10] # Search trends search_trends = SearchAnalytics.objects.extra( select={'date': 'DATE(created_at)'} ).values('date').annotate( count=Count('id') ).order_by('date') context = { 'analytics': analytics, 'popular_searches': popular_searches, 'search_trends': search_trends, } return render(request, 'search/analytics.html', context) def search_api(request): """REST API für Search""" query = request.GET.get('q', '') filters = request.GET.get('filters', '{}') try: filters = json.loads(filters) except json.JSONDecodeError: filters = {} # Build search query sqs = SearchQuerySet() if query: sqs = sqs.filter(text=AutoQuery(query)) # Apply filters for key, value in filters.items(): if value: sqs = sqs.filter(**{key: value}) # Pagination page = request.GET.get('page', 1) per_page = request.GET.get('per_page', 20) paginator = Paginator(sqs, per_page) page_obj = paginator.get_page(page) # Format results results = [] for result in page_obj: results.append({ 'id': result.pk, 'title': result.title, 'description': result.description, 'url': result.url, 'type': result.model_name, 'score': result.score, }) return JsonResponse({ 'results': results, 'total': len(sqs), 'page': page, 'per_page': per_page, 'pages': paginator.num_pages, }) def track_search_analytics(request, query, result_count): """Track search analytics""" if not query or not settings.SEARCH_SETTINGS.get('ENABLE_SEARCH_ANALYTICS', True): return from search.models import SearchAnalytics SearchAnalytics.objects.create( query=query, user=request.user if request.user.is_authenticated else None, result_count=result_count, ip_address=request.META.get('REMOTE_ADDR'), user_agent=request.META.get('HTTP_USER_AGENT', ''), ) def search_autocomplete(request): """Enhanced Autocomplete mit Fuzzy Search""" query = request.GET.get('q', '') if len(query) < 2: return JsonResponse({'suggestions': []}) # Product suggestions product_sqs = SearchQuerySet().models(Product).autocomplete( title_auto=query )[:5] # Auction suggestions auction_sqs = SearchQuerySet().models(Auction).autocomplete( title_auto=query )[:5] suggestions = [] # Add product suggestions for product in product_sqs: suggestions.append({ 'title': product.title, 'type': 'product', 'category': product.category, 'price': float(product.price), 'url': f'/products/{product.pk}/', }) # Add auction suggestions for auction in auction_sqs: suggestions.append({ 'title': auction.title, 'type': 'auction', 'status': auction.status, 'current_bid': float(auction.current_bid) if auction.current_bid else 0, 'url': f'/auction/{auction.pk}/', }) return JsonResponse({'suggestions': suggestions}) def search_faceted(request): """Faceted Search API""" query = request.GET.get('q', '') facets = request.GET.getlist('facets') sqs = SearchQuerySet() if query: sqs = sqs.filter(text=AutoQuery(query)) # Apply facets for facet in facets: if ':' in facet: field, value = facet.split(':', 1) sqs = sqs.filter(**{field: value}) # Get facet counts facet_counts = {} for field in ['category', 'fursuit_type', 'status']: facet_counts[field] = sqs.facet(field).facet_counts()['fields'].get(field, []) # Price ranges price_ranges = [ {'range': '0-100', 'count': sqs.filter(price__range=(0, 100)).count()}, {'range': '100-500', 'count': sqs.filter(price__range=(100, 500)).count()}, {'range': '500-1000', 'count': sqs.filter(price__range=(500, 1000)).count()}, {'range': '1000+', 'count': sqs.filter(price__gte=1000).count()}, ] return JsonResponse({ 'facets': facet_counts, 'price_ranges': price_ranges, 'total': len(sqs), })