updated search autocomplete

This commit is contained in:
nvrl committed 2026-02-16 19:25:41 +01:00
1 parent 6b58dbe9fb
commit f4f8ecef34
3 files changed
+24 -6

No files matched your search

+18 -2
View File
@@ -1,5 +1,5 @@
from django.core.mail import send_mail
from rest_framework import viewsets, permissions, status
from rest_framework import viewsets, permissions, status, filters
from rest_framework.response import Response
from rest_framework.decorators import action
from django.db.models import Avg
@@ -12,13 +12,29 @@ from .serializers import UserSerializer, FlavorSerializer, CategorySerializer, R
class FlavorViewSet(viewsets.ModelViewSet):
queryset = Flavor.objects.annotate(average_rating=Avg('ratings__score')).order_by('-average_rating')
serializer_class = FlavorSerializer
filter_backends = [DjangoFilterBackend]
filter_backends = [DjangoFilterBackend, filters.SearchFilter]
filterset_fields = ['category', 'category__slug']
search_fields = ['name', 'description']
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
def get_queryset(self):
return Flavor.objects.select_related('category').annotate(average_rating=Avg('ratings__score')).order_by('-average_rating')
@action(detail=False, methods=['get'], permission_classes=[permissions.AllowAny])
def search(self, request):
# Unpaginated list of all flavors for the search autocomplete
flavors = Flavor.objects.select_related('category').order_by('name')
data = [
{
'id': f.id,
'name': f.name,
'image_url': request.build_absolute_uri(f.image.url) if f.image else f.image_url,
'category_name': f.category.name
}
for f in flavors
]
return Response(data)
@action(detail=False, methods=['get'], permission_classes=[permissions.AllowAny])
def top(self, request):
top_flavors = self.get_queryset().filter(ratings__isnull=False).distinct()[:10]
+4 -3
View File
@@ -57,14 +57,15 @@ const GlobalSearch = () => {
useEffect(() => {
const fetchFlavors = async () => {
try {
const res = await api.get('flavors/');
setOptions(Array.isArray(res.data) ? res.data : (res.data.results || []));
// Fetch from unpaginated search endpoint for full catalog coverage
const res = await api.get('flavors/search/');
setOptions(res.data);
} catch (err) {
console.error('Failed to fetch search options');
}
};
fetchFlavors();
}, []);
}, []); // Only fetch once to avoid excessive API calls
useEffect(() => {
const params = new URLSearchParams(location.search);
+2 -1
View File
@@ -68,7 +68,8 @@ const CategoryList: React.FC = () => {
setLoading(true);
try {
if (query) {
const res = await api.get(`flavors/`);
// Perform server-side search to get all matching flavors across pages
const res = await api.get(`flavors/?search=${encodeURIComponent(query)}`);
setAllFlavors(Array.isArray(res.data) ? res.data : (res.data.results || []));
} else {
const [catRes, topRes, recentRes] = await Promise.all([