Files
tripwithbonus/backend/api/search/views.py
2025-05-29 11:48:33 +03:00

103 lines
4.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from rest_framework import generics
from rest_framework.request import Request as DRFRequest
from typing import cast
from routes.models import Route
from .serializers import SearchRouteSerializer
from api.utils.pagination import StandardResultsSetPagination
from rest_framework.exceptions import ValidationError
from routes.constants.routeChoices import owner_type_choices
from django.utils import timezone
from django.db.models import Q
from urllib.parse import unquote
from api.utils.cityVariator import get_city_variations
from django.db.models.functions import Coalesce
class SearchRouteListView(generics.ListAPIView):
serializer_class = SearchRouteSerializer
pagination_class = StandardResultsSetPagination
def get_queryset(self):
request = cast(DRFRequest, self.request)
owner_type = self.kwargs.get('owner_type')
# получаем маршрут из URL и разбиваем его на города
route = self.kwargs.get('route', '')
if route:
# декодируем URL дважды, так как он может быть дважды закодирован
route = unquote(unquote(route))
try:
from_city, to_city = route.split('-', 1)
except ValueError:
from_city = to_city = None
else:
# если маршрут не указан в URL, берем из query params и декодируем
from_city = request.query_params.get('from', '')
to_city = request.query_params.get('to', '')
# декодируем значения, если они закодированы
if from_city:
try:
# пробуем декодировать дважды для случая двойного кодирования
from_city = unquote(from_city)
if '%' in from_city: # если после первого декодирования остались %-коды
from_city = unquote(from_city)
except Exception as e:
print(f"Error decoding from_city: {e}")
if to_city:
try:
# пробуем декодировать дважды для случая двойного кодирования
to_city = unquote(to_city)
if '%' in to_city: # если после первого декодирования остались %-коды
to_city = unquote(to_city)
except Exception as e:
print(f"Error decoding to_city: {e}")
valid_types = [choice[0] for choice in owner_type_choices]
current_time = timezone.now()
if not owner_type or owner_type not in valid_types:
raise ValidationError("Invalid or missing owner_type. Must be either 'customer' or 'mover'")
# базовый фильтр по типу владельца и актуальности
queryset = Route.objects.all()
# Применяем базовые фильтры
queryset = queryset.filter(owner_type=owner_type, status='actual')
# фильтруем по городам если они указаны
if from_city:
# Получаем варианты написания для поиска
from_city_variations = get_city_variations(from_city)
# Используем Q objects для поиска по обоим полям
from_city_filter = (
Q(from_city__name__in=from_city_variations) |
Q(from_city__russian_name__in=from_city_variations)
)
queryset = queryset.filter(from_city_filter)
if to_city:
# получаем варианты написания для поиска
to_city_variations = get_city_variations(to_city)
# используем Q objects для поиска по обоим полям
to_city_filter = (
Q(to_city__name__in=to_city_variations) |
Q(to_city__russian_name__in=to_city_variations)
)
queryset = queryset.filter(to_city_filter)
# фильтруем по времени в зависимости от типа
if owner_type == 'mover':
queryset = queryset.filter(departure_DT__gt=current_time)
else: # customer
queryset = queryset.filter(arrival_DT__gt=current_time)
# премиум мембершип -- добавляем аннотацию и сортируем по последнему поднятию или дате создания
queryset = queryset.annotate(
sort_time=Coalesce('rising_DT', 'created_at')
).order_by('-sort_time')
return queryset