Files
tripwithbonus/backend/api/search/views.py
2025-05-27 11:56:42 +03:00

132 lines
6.1 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
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')