132 lines
6.1 KiB
Python
132 lines
6.1 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
|
||
import cyrtranslit
|
||
from urllib.parse import unquote
|
||
|
||
def get_city_variations(city_name: str) -> list[str]:
|
||
"""
|
||
Получает варианты написания города, включая транслитерацию
|
||
"""
|
||
variations = set()
|
||
|
||
# добавляем оригинальное название и его варианты с разным регистром
|
||
variations.add(city_name)
|
||
variations.add(city_name.lower())
|
||
variations.add(city_name.title())
|
||
|
||
# пробуем добавить транслитерации
|
||
try:
|
||
# пробуем транслитерировать в обе стороны
|
||
lat = cyrtranslit.to_latin(city_name, 'ru')
|
||
cyr = cyrtranslit.to_cyrillic(city_name, 'ru')
|
||
|
||
# добавляем варианты транслитерации с разным регистром
|
||
for variant in [lat, cyr]:
|
||
variations.add(variant)
|
||
variations.add(variant.lower())
|
||
variations.add(variant.title())
|
||
except:
|
||
pass
|
||
|
||
return list(variations)
|
||
|
||
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', '')
|
||
print(f"Raw route from URL: {route}")
|
||
|
||
if route:
|
||
# декодируем URL дважды, так как он может быть дважды закодирован
|
||
route = unquote(unquote(route))
|
||
print(f"Decoded route: {route}")
|
||
try:
|
||
from_city, to_city = route.split('-', 1)
|
||
print(f"Split cities - from: {from_city}, to: {to_city}")
|
||
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}")
|
||
|
||
print(f"Query params - from: {from_city}, to: {to_city}")
|
||
|
||
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:
|
||
print(f"Searching for from_city: {from_city}")
|
||
# Получаем варианты написания для поиска
|
||
from_city_variations = get_city_variations(from_city)
|
||
print(f"From city variations: {from_city_variations}")
|
||
# Используем 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:
|
||
print(f"Searching for to_city: {to_city}")
|
||
# получаем варианты написания для поиска
|
||
to_city_variations = get_city_variations(to_city)
|
||
print(f"To city variations: {to_city_variations}")
|
||
# используем 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)
|
||
|
||
return queryset.order_by('-arrival_DT')
|