103 lines
4.9 KiB
Python
103 lines
4.9 KiB
Python
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
|