mirror of
https://github.com/narrrl/holy-flavor-rater.git
synced 2026-11-03 16:41:27 +01:00
updated search autocomplete
This commit is contained in:
1 parent
6b58dbe9fb
commit
f4f8ecef34
3 files changed
+24
-6
No files matched your search
+18
-2
@@ -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]
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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([
|
||||
|
||||
Reference in new issue
Block a user