mirror of
https://github.com/task-17-lct/backend.git
synced 2024-11-14 09:36:33 +03:00
Merge branch 'remove-bugs'
This commit is contained in:
commit
bc173cdbee
270
passfinder/city.txt
Normal file
270
passfinder/city.txt
Normal file
|
@ -0,0 +1,270 @@
|
||||||
|
Москва
|
||||||
|
|
||||||
|
|
||||||
|
Санкт-Петербург
|
||||||
|
|
||||||
|
|
||||||
|
Новосибирск
|
||||||
|
|
||||||
|
|
||||||
|
Екатеринбург
|
||||||
|
|
||||||
|
|
||||||
|
Нижний Новгород
|
||||||
|
|
||||||
|
|
||||||
|
Самара
|
||||||
|
|
||||||
|
|
||||||
|
Омск
|
||||||
|
|
||||||
|
|
||||||
|
Казань
|
||||||
|
|
||||||
|
|
||||||
|
Челябинск
|
||||||
|
|
||||||
|
|
||||||
|
Ростов-на-Дону
|
||||||
|
|
||||||
|
|
||||||
|
Уфа
|
||||||
|
|
||||||
|
|
||||||
|
Волгоград
|
||||||
|
|
||||||
|
|
||||||
|
Пермь
|
||||||
|
|
||||||
|
|
||||||
|
Красноярск
|
||||||
|
|
||||||
|
Воронеж
|
||||||
|
|
||||||
|
Саратов
|
||||||
|
|
||||||
|
Краснодар
|
||||||
|
|
||||||
|
Тольятти
|
||||||
|
|
||||||
|
Ижевск
|
||||||
|
|
||||||
|
Ульяновск
|
||||||
|
|
||||||
|
Барнаул
|
||||||
|
|
||||||
|
Владивосток
|
||||||
|
|
||||||
|
Ярославль
|
||||||
|
|
||||||
|
Иркутск
|
||||||
|
|
||||||
|
Тюмень
|
||||||
|
|
||||||
|
Махачкала
|
||||||
|
|
||||||
|
Хабаровск
|
||||||
|
|
||||||
|
Оренбург
|
||||||
|
|
||||||
|
Новокузнецк
|
||||||
|
|
||||||
|
Кемерово
|
||||||
|
|
||||||
|
Рязань
|
||||||
|
|
||||||
|
Томск
|
||||||
|
|
||||||
|
Астрахань
|
||||||
|
|
||||||
|
Пенза
|
||||||
|
|
||||||
|
Набережные Челны
|
||||||
|
|
||||||
|
Липецк
|
||||||
|
|
||||||
|
Тула
|
||||||
|
|
||||||
|
Киров
|
||||||
|
|
||||||
|
Чебоксары
|
||||||
|
|
||||||
|
Калининград
|
||||||
|
|
||||||
|
Брянск
|
||||||
|
|
||||||
|
Курск
|
||||||
|
|
||||||
|
Иваново
|
||||||
|
|
||||||
|
Магнитогорск
|
||||||
|
|
||||||
|
Улан-Удэ
|
||||||
|
|
||||||
|
Тверь
|
||||||
|
|
||||||
|
Ставрополь
|
||||||
|
|
||||||
|
Нижний Тагил
|
||||||
|
|
||||||
|
Белгород
|
||||||
|
|
||||||
|
Архангельск
|
||||||
|
|
||||||
|
Владимир
|
||||||
|
|
||||||
|
Сочи
|
||||||
|
|
||||||
|
Курган
|
||||||
|
|
||||||
|
Смоленск
|
||||||
|
|
||||||
|
Калуга
|
||||||
|
|
||||||
|
Чита
|
||||||
|
|
||||||
|
Ор
|
||||||
|
л
|
||||||
|
|
||||||
|
Волжский
|
||||||
|
|
||||||
|
Череповец
|
||||||
|
|
||||||
|
Владикавказ
|
||||||
|
|
||||||
|
Мурманск
|
||||||
|
|
||||||
|
Сургут
|
||||||
|
|
||||||
|
Вологда
|
||||||
|
|
||||||
|
Саранск
|
||||||
|
|
||||||
|
Тамбов
|
||||||
|
|
||||||
|
Стерлитамак
|
||||||
|
|
||||||
|
Грозный
|
||||||
|
|
||||||
|
Якутск
|
||||||
|
|
||||||
|
Кострома
|
||||||
|
|
||||||
|
Комсомольск-на-Амуре
|
||||||
|
|
||||||
|
Петрозаводск
|
||||||
|
|
||||||
|
Таганрог
|
||||||
|
|
||||||
|
Нижневартовск
|
||||||
|
|
||||||
|
Йошкар-Ола
|
||||||
|
|
||||||
|
Братск
|
||||||
|
|
||||||
|
Новороссийск
|
||||||
|
|
||||||
|
Дзержинск
|
||||||
|
|
||||||
|
Шахты
|
||||||
|
|
||||||
|
Нальчик
|
||||||
|
|
||||||
|
Орск
|
||||||
|
|
||||||
|
Сыктывкар
|
||||||
|
|
||||||
|
Нижнекамск
|
||||||
|
|
||||||
|
Ангарск
|
||||||
|
|
||||||
|
Старый Оскол
|
||||||
|
|
||||||
|
Великий Новгород
|
||||||
|
|
||||||
|
Балашиха
|
||||||
|
|
||||||
|
Благовещенск
|
||||||
|
|
||||||
|
Прокопьевск
|
||||||
|
|
||||||
|
Бийск
|
||||||
|
|
||||||
|
Химки
|
||||||
|
|
||||||
|
Псков
|
||||||
|
|
||||||
|
Энгельс
|
||||||
|
|
||||||
|
Рыбинск
|
||||||
|
|
||||||
|
Балаково
|
||||||
|
|
||||||
|
Северодвинск
|
||||||
|
|
||||||
|
Армавир
|
||||||
|
|
||||||
|
Подольск
|
||||||
|
|
||||||
|
Корол
|
||||||
|
в
|
||||||
|
|
||||||
|
Южно-Сахалинск
|
||||||
|
|
||||||
|
Петропавловск-Камчатский
|
||||||
|
|
||||||
|
Сызрань
|
||||||
|
|
||||||
|
Норильск
|
||||||
|
|
||||||
|
Златоуст
|
||||||
|
|
||||||
|
Каменск-Уральский
|
||||||
|
|
||||||
|
Мытищи
|
||||||
|
|
||||||
|
Люберцы
|
||||||
|
|
||||||
|
Волгодонск
|
||||||
|
|
||||||
|
Новочеркасск
|
||||||
|
|
||||||
|
Абакан
|
||||||
|
|
||||||
|
Находка
|
||||||
|
|
||||||
|
Уссурийск
|
||||||
|
|
||||||
|
Березники
|
||||||
|
|
||||||
|
Салават
|
||||||
|
|
||||||
|
Электросталь
|
||||||
|
|
||||||
|
Миасс
|
||||||
|
|
||||||
|
Первоуральск
|
||||||
|
|
||||||
|
Рубцовск
|
||||||
|
|
||||||
|
Альметьевск
|
||||||
|
|
||||||
|
Ковров
|
||||||
|
|
||||||
|
Коломна
|
||||||
|
|
||||||
|
Майкоп
|
||||||
|
|
||||||
|
Пятигорск
|
||||||
|
|
||||||
|
Одинцово
|
||||||
|
|
||||||
|
Колпино
|
||||||
|
|
||||||
|
Копейск
|
||||||
|
|
||||||
|
Хасавюрт
|
||||||
|
Новомосковск
|
||||||
|
Кисловодск
|
||||||
|
Серпухов
|
||||||
|
Новочебоксарск
|
|
@ -1,226 +1,47 @@
|
||||||
city_in_hotels = ['Абзаково',
|
city_in_hotels = {'Астрахань',
|
||||||
'Абрамовка',
|
|
||||||
'Абрау-Дюрсо',
|
|
||||||
'Адлер',
|
|
||||||
'Азов',
|
|
||||||
'Аксай',
|
|
||||||
'Альметьевск',
|
|
||||||
'Анапа',
|
|
||||||
'Андрианово',
|
|
||||||
'Арамиль',
|
|
||||||
'Арзамас',
|
|
||||||
'Арнеево',
|
|
||||||
'Архипо-Осиповка',
|
|
||||||
'Бабкино',
|
|
||||||
'Базы отдыха ВТО',
|
|
||||||
'Балашиха',
|
'Балашиха',
|
||||||
'Батайск',
|
'Березники',
|
||||||
'Беличье',
|
'Благовещенск',
|
||||||
'Белореченск',
|
'Владикавказ',
|
||||||
'Бердск',
|
'Волгоград',
|
||||||
'Бердяш',
|
'Волгодонск',
|
||||||
'Березовка',
|
'Волжский',
|
||||||
'Бжид',
|
'Воронеж',
|
||||||
'Битца',
|
'Грозный',
|
||||||
'Благовещенская',
|
|
||||||
'Болтино',
|
|
||||||
'Большой Сочи',
|
|
||||||
'Бор, Нижегородская область',
|
|
||||||
'Борисово',
|
|
||||||
'Борносово',
|
|
||||||
'Будённовск',
|
|
||||||
'Вардане',
|
|
||||||
'Васильево, Ленинградская область',
|
|
||||||
'Васкелово',
|
|
||||||
'Вербилки',
|
|
||||||
'Веселовка, Краснодарский край',
|
|
||||||
'Видное',
|
|
||||||
'Витязево',
|
|
||||||
'Владимировка',
|
|
||||||
'Внуково',
|
|
||||||
'Воскресенск',
|
|
||||||
'Вотря',
|
|
||||||
'Всеволожск',
|
|
||||||
'Всходы',
|
|
||||||
'Выборг',
|
|
||||||
'Вырубово',
|
|
||||||
'Гатчина',
|
|
||||||
'Гвардейское',
|
|
||||||
'Геленджик',
|
|
||||||
'Голиково',
|
|
||||||
'Головинка Краснодарский край',
|
|
||||||
'Голубицкая',
|
|
||||||
'Горки',
|
|
||||||
'Городец',
|
|
||||||
'Горячий ключ',
|
|
||||||
'Григорчиково',
|
|
||||||
'Гуамка',
|
|
||||||
'Д/О Авангард',
|
|
||||||
'Дагомыс',
|
|
||||||
'Джемете',
|
|
||||||
'Джубга',
|
|
||||||
'Дзержинск',
|
'Дзержинск',
|
||||||
'Дивеево',
|
|
||||||
'Дивногорье, Краснодарский край',
|
|
||||||
'Дивноморское',
|
|
||||||
'Дмитров',
|
|
||||||
'Домодедово',
|
|
||||||
'Дракино',
|
|
||||||
'Дранишники',
|
|
||||||
'Дубечино',
|
|
||||||
'Егорьевск',
|
|
||||||
'Ейск',
|
|
||||||
'Екатеринбург',
|
'Екатеринбург',
|
||||||
'Ершово',
|
'Златоуст',
|
||||||
'Ессентуки',
|
'Ижевск',
|
||||||
'Железноводск',
|
'Каменск-Уральский',
|
||||||
'Жуковский',
|
'Киров',
|
||||||
'За Родину',
|
|
||||||
'Звенигород',
|
|
||||||
'Зеленая поляна',
|
|
||||||
'Ивантеевка',
|
|
||||||
'Ильичево',
|
|
||||||
'Иннолово ',
|
|
||||||
'Иноземцево',
|
|
||||||
'Исаково',
|
|
||||||
'Истра',
|
|
||||||
'Кабардинка',
|
|
||||||
'Казань',
|
|
||||||
'Каменск-Шахтинский',
|
|
||||||
'Каневская',
|
|
||||||
'Кингисепп',
|
|
||||||
'Кисловодск',
|
'Кисловодск',
|
||||||
'Клин',
|
'Колпино',
|
||||||
'Коломна',
|
'Комсомольск-на-Амуре',
|
||||||
'Коробицыно',
|
'Копейск',
|
||||||
'Королев',
|
'Кострома',
|
||||||
'Косулино',
|
'Красноярск',
|
||||||
'Котельники',
|
'Курган',
|
||||||
'Красная Горка',
|
|
||||||
'Красная Поляна',
|
|
||||||
'Красногорск',
|
|
||||||
'Краснодар',
|
|
||||||
'Красный Колос',
|
|
||||||
'Кудряшовский',
|
|
||||||
'Курово',
|
|
||||||
'Кусимовского Рудника',
|
|
||||||
'Кучугуры',
|
|
||||||
'Лабинск',
|
|
||||||
'Лазаревское',
|
|
||||||
'Лермонтово',
|
|
||||||
'Лесной городок',
|
|
||||||
'Лодейное Поле',
|
|
||||||
'Лоо',
|
|
||||||
'Лосево',
|
|
||||||
'Люберцы',
|
'Люберцы',
|
||||||
'Магнитогорск',
|
'Магнитогорск',
|
||||||
'Малые Решники',
|
'Махачкала',
|
||||||
'Марьино, Ленинградская область',
|
|
||||||
'Маяковского',
|
|
||||||
'Мезмай',
|
|
||||||
'Мещерино',
|
|
||||||
'Миасс',
|
|
||||||
'Минеральные Воды',
|
|
||||||
'Мистолово',
|
|
||||||
'Мишуткино',
|
|
||||||
'Можайск',
|
|
||||||
'Москва',
|
'Москва',
|
||||||
'Мостовской',
|
|
||||||
'Мытищи',
|
'Мытищи',
|
||||||
'Набережные Челны',
|
'Нальчик',
|
||||||
'Наро-Фоминск',
|
'Нижнекамск',
|
||||||
'Нарынка',
|
|
||||||
'Небуг',
|
|
||||||
'Нестерово',
|
|
||||||
'Нижний Новгород',
|
|
||||||
'Нижний Тагил',
|
'Нижний Тагил',
|
||||||
'Новая',
|
'Новочебоксарск',
|
||||||
'Новоабзаково',
|
|
||||||
'Нововолково',
|
|
||||||
'Новомихайловский',
|
|
||||||
'Новороссийск',
|
|
||||||
'Новосибирск',
|
|
||||||
'Новочеркасск',
|
|
||||||
'Новый путь',
|
|
||||||
'Ногинск',
|
|
||||||
'Нурлат',
|
|
||||||
'Овсяники',
|
|
||||||
'Одинцово',
|
'Одинцово',
|
||||||
'Озеры',
|
'Омск',
|
||||||
'Оксино',
|
'Оренбург',
|
||||||
'Октябрьский, Московская область',
|
'Орск',
|
||||||
'Ольгинка',
|
'Пермь',
|
||||||
'Остров, Московская область',
|
|
||||||
'Павловск',
|
|
||||||
'Падиково',
|
|
||||||
'Пересвет',
|
|
||||||
'Платформа 69-й километр, Сосновское сельское поселение',
|
|
||||||
'Подольск',
|
'Подольск',
|
||||||
'Подпорожье',
|
|
||||||
'Полтавская',
|
|
||||||
'Приморско-Ахтарск',
|
|
||||||
'Приозерск',
|
|
||||||
'Прохорово',
|
|
||||||
'Пушкино',
|
|
||||||
'Пятигорск',
|
'Пятигорск',
|
||||||
'Раменское',
|
'Салават',
|
||||||
'Реутов',
|
|
||||||
'Рождествено',
|
|
||||||
'Роза Хутор',
|
|
||||||
'Ростов-на-Дону',
|
|
||||||
'Рощино',
|
|
||||||
'Руза',
|
|
||||||
'Санкт-Петербург',
|
'Санкт-Петербург',
|
||||||
'Светлое',
|
'Томск',
|
||||||
'Светлый',
|
|
||||||
'Свирица',
|
|
||||||
'Сергиев Посад',
|
|
||||||
'Серпухов',
|
|
||||||
'Симагино',
|
|
||||||
'Сириус',
|
|
||||||
'Скоково',
|
|
||||||
'Снегири',
|
|
||||||
'Солнечногорск',
|
|
||||||
'Солохаул',
|
|
||||||
'Сосново',
|
|
||||||
'Сосновый Бор, Ленинградская область',
|
|
||||||
'Сосновый Бор, Московская область',
|
|
||||||
'Софрино',
|
|
||||||
'Сочи',
|
|
||||||
'Ставрополь',
|
|
||||||
'Станица Динская',
|
|
||||||
'Станица Должанская',
|
|
||||||
'Старая Руза',
|
|
||||||
'Степаньково',
|
|
||||||
'Суйда',
|
|
||||||
'Сукко',
|
|
||||||
'Супсех',
|
|
||||||
'Таганрог',
|
|
||||||
'Тарасово',
|
|
||||||
'Тимашевск',
|
|
||||||
'Тихвин',
|
|
||||||
'Тихорецк',
|
|
||||||
'Тобольск',
|
|
||||||
'Туапсе',
|
|
||||||
'Тучково',
|
|
||||||
'Тюмень',
|
'Тюмень',
|
||||||
'Увильды ',
|
|
||||||
'Углегорский',
|
|
||||||
'Удельная',
|
|
||||||
'Усть-Койсуг',
|
|
||||||
'Усть-Лабинск',
|
|
||||||
'Уфа',
|
'Уфа',
|
||||||
'Ушаки',
|
'Хасавюрт',
|
||||||
'Фрязино',
|
|
||||||
'Хадыженск',
|
|
||||||
'Химки',
|
'Химки',
|
||||||
'Хоста',
|
'Энгельс'}
|
||||||
'Чебаркуль',
|
|
||||||
'Челябинск',
|
|
||||||
'Чехов, Сахалинская область',
|
|
||||||
'Чудская',
|
|
||||||
'Шахты',
|
|
||||||
'Широкая балка',
|
|
||||||
'Щёлково',
|
|
||||||
'Эсто-Садок',
|
|
||||||
'Якорная щель']
|
|
|
@ -65,6 +65,49 @@ class RouteInputSerializer(serializers.Serializer):
|
||||||
min_length=24, max_length=24, required=False, allow_blank=True, allow_null=True
|
min_length=24, max_length=24, required=False, allow_blank=True, allow_null=True
|
||||||
)
|
)
|
||||||
movement = serializers.ChoiceField(['walk', 'bike', 'scooter', 'auto'], required=False, allow_blank=True)
|
movement = serializers.ChoiceField(['walk', 'bike', 'scooter', 'auto'], required=False, allow_blank=True)
|
||||||
|
stars = serializers.ListField(
|
||||||
|
child=serializers.ChoiceField([1, 2, 3, 4, 5]),
|
||||||
|
required=False,
|
||||||
|
allow_empty=True,
|
||||||
|
allow_null=True
|
||||||
|
)
|
||||||
|
what_to_see = serializers.ListField(
|
||||||
|
child=serializers.ChoiceField(
|
||||||
|
[
|
||||||
|
'attractions',
|
||||||
|
'museum',
|
||||||
|
'movie',
|
||||||
|
'concert',
|
||||||
|
'artwork',
|
||||||
|
'plays',
|
||||||
|
'shop',
|
||||||
|
'gallery',
|
||||||
|
'theme_park',
|
||||||
|
'viewpoint',
|
||||||
|
'zoo'
|
||||||
|
]
|
||||||
|
),
|
||||||
|
required=False,
|
||||||
|
allow_empty=True,
|
||||||
|
allow_null=True
|
||||||
|
)
|
||||||
|
where_stay = serializers.ListField(
|
||||||
|
child=serializers.ChoiceField([
|
||||||
|
'hotel', 'apartment', 'hostel'
|
||||||
|
]),
|
||||||
|
required=False,
|
||||||
|
allow_empty=True,
|
||||||
|
allow_null=True
|
||||||
|
)
|
||||||
|
where_eat = serializers.ListField(
|
||||||
|
child=serializers.ChoiceField(['restaurant', 'bar', 'cafe']),
|
||||||
|
required=False,
|
||||||
|
allow_empty=True,
|
||||||
|
allow_null=True
|
||||||
|
)
|
||||||
|
with_kids = serializers.BooleanField(required=False, allow_null=True)
|
||||||
|
with_animals = serializers.BooleanField(required=False, allow_null=True)
|
||||||
|
|
||||||
|
|
||||||
class CitySerializer(serializers.ModelSerializer):
|
class CitySerializer(serializers.ModelSerializer):
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
@ -75,6 +75,40 @@ def post(self, request):
|
||||||
movement = data['movement']
|
movement = data['movement']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
movement = 'walk'
|
movement = 'walk'
|
||||||
|
|
||||||
|
hotel_stars = data['stars']
|
||||||
|
if hotel_stars is None:
|
||||||
|
hotel_stars = []
|
||||||
|
|
||||||
|
|
||||||
|
hotel_type = data['where_stay']
|
||||||
|
if hotel_type is None:
|
||||||
|
hotel_type = ['hotel']
|
||||||
|
|
||||||
|
where_eat = data['where_eat']
|
||||||
|
if where_eat is None:
|
||||||
|
where_eat = ['restaurant', 'bar', 'cafe']
|
||||||
|
|
||||||
|
what_to_see = data['what_to_see']
|
||||||
|
if what_to_see is None:
|
||||||
|
what_to_see = [
|
||||||
|
'attractions',
|
||||||
|
'museum',
|
||||||
|
'movie',
|
||||||
|
'concert',
|
||||||
|
'artwork',
|
||||||
|
'plays',
|
||||||
|
'shop',
|
||||||
|
'gallery',
|
||||||
|
'theme_park',
|
||||||
|
'viewpoint',
|
||||||
|
'zoo'
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
if 'hotel' not in hotel_type:
|
||||||
|
hotel_stars = []
|
||||||
|
|
||||||
region = None
|
region = None
|
||||||
|
|
||||||
if city_id:
|
if city_id:
|
||||||
|
@ -95,7 +129,17 @@ def post(self, request):
|
||||||
|
|
||||||
print(request.user, region, start_date, end_date)
|
print(request.user, region, start_date, end_date)
|
||||||
|
|
||||||
tour = generate_tour(request.user, region, start_date, end_date, movement_mapping[movement])
|
tour = generate_tour(
|
||||||
|
request.user,
|
||||||
|
region,
|
||||||
|
start_date,
|
||||||
|
end_date,
|
||||||
|
avg_velocity=movement_mapping[movement],
|
||||||
|
stars=hotel_stars,
|
||||||
|
hotel_type=hotel_type,
|
||||||
|
where_eat=where_eat,
|
||||||
|
what_to_see=what_to_see
|
||||||
|
)
|
||||||
print(len(tour[1]))
|
print(len(tour[1]))
|
||||||
|
|
||||||
return Response(data=tour[0])
|
return Response(data=tour[0])
|
||||||
|
@ -109,9 +153,7 @@ class ListRegionApiView(ListAPIView):
|
||||||
class ListCityApiView(ListAPIView):
|
class ListCityApiView(ListAPIView):
|
||||||
serializer_class = CitySerializer
|
serializer_class = CitySerializer
|
||||||
queryset = (
|
queryset = (
|
||||||
City.objects.annotate(points_num=Count("points"))
|
City.objects.annotate(points_count=Count('points')).filter(title__in=city_in_hotels).filter(points_count__gt=200).order_by('title')
|
||||||
.filter(points_num__gte=100)
|
|
||||||
.order_by("title")
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from passfinder.events.api.serializers import EventSerializer, HotelSerializer
|
from passfinder.events.api.serializers import EventSerializer, HotelSerializer, ObjectRouteSerializer
|
||||||
|
|
||||||
|
|
||||||
class TinderProceedSerializer(serializers.Serializer):
|
class TinderProceedSerializer(serializers.Serializer):
|
||||||
|
@ -49,3 +49,23 @@ class DailySelectionSerializer(serializers.Serializer):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
event = EventSerializer()
|
event = EventSerializer()
|
||||||
|
|
||||||
|
|
||||||
|
class StarSelectionSerializer(serializers.Serializer):
|
||||||
|
stars = serializers.ListField(child=serializers.IntegerField(), write_only=True)
|
||||||
|
|
||||||
|
|
||||||
|
class CategorySelectionSerializer(serializers.Serializer):
|
||||||
|
categories = serializers.ListField(child=serializers.ChoiceField(
|
||||||
|
['attractions', 'museum', 'movie', 'concert', 'artwork', 'plays', 'shop', 'gallery', 'theme_park', 'viewpoint', 'zoo']
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
class RecomendationNode(serializers.Serializer):
|
||||||
|
category = serializers.CharField()
|
||||||
|
events = serializers.ListField(child=ObjectRouteSerializer())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class SelfRecomendationSerializer(serializers.Serializer):
|
||||||
|
recomendations = serializers.ListField(child=RecomendationNode(), write_only=True)
|
|
@ -49,32 +49,13 @@ class PersonalRecommendation(viewsets.GenericViewSet):
|
||||||
model = Event
|
model = Event
|
||||||
queryset = Event.objects.all()
|
queryset = Event.objects.all()
|
||||||
|
|
||||||
@action(methods=['GET'], detail=False)
|
|
||||||
def plays(self, request, *args, **kwargs):
|
|
||||||
recs = get_personal_plays_recommendation(request.user)
|
|
||||||
ans = []
|
|
||||||
for rec in recs:
|
|
||||||
ans.append(EventSerializer(rec[1]).data)
|
|
||||||
return Response(ans, 200)
|
|
||||||
|
|
||||||
|
|
||||||
@action(methods=['GET'], detail=False)
|
|
||||||
def concerts(self, request, *args, **kwargs):
|
|
||||||
recs = get_personal_concerts_recommendation(request.user)
|
|
||||||
ans = []
|
|
||||||
for rec in recs:
|
|
||||||
ans.append(EventSerializer(rec[1]).data)
|
|
||||||
return Response(ans, 200)
|
|
||||||
|
|
||||||
|
|
||||||
@action(methods=['GET'], detail=False)
|
|
||||||
def movies(self, request, *args, **kwargs):
|
|
||||||
recs = get_personal_movies_recommendation(request.user)
|
|
||||||
ans = []
|
|
||||||
for rec in recs:
|
|
||||||
ans.append(EventSerializer(rec[1]).data)
|
|
||||||
return Response(ans, 200)
|
|
||||||
|
|
||||||
|
@action(methods=['GET'], detail=False, serializer_class=SelfRecomendationSerializer)
|
||||||
|
def recommendations(self, request, *args, **kwargs):
|
||||||
|
return Response(
|
||||||
|
data=get_personal_recomendations(request.user),
|
||||||
|
status=200
|
||||||
|
)
|
||||||
|
|
||||||
@action(methods=['GET'], detail=True)
|
@action(methods=['GET'], detail=True)
|
||||||
def get_nearest_user_distance(self, request, pk, *args, **kwargs):
|
def get_nearest_user_distance(self, request, pk, *args, **kwargs):
|
||||||
|
@ -166,3 +147,17 @@ def add_to_favorites(self, request, pk, *args, **kwargs):
|
||||||
pref.save()
|
pref.save()
|
||||||
|
|
||||||
return Response(status=200)
|
return Response(status=200)
|
||||||
|
|
||||||
|
@action(methods=['POST'], detail=False, serializer_class=StarSelectionSerializer)
|
||||||
|
def set_hotel_stars(self, request, *args, **kwargs):
|
||||||
|
up, _ = UserPreferences.objects.get_or_create(user=request.user)
|
||||||
|
up.preferred_stars = request.data['stars']
|
||||||
|
up.save()
|
||||||
|
return Response(status=200)
|
||||||
|
|
||||||
|
@action(methods=['POST'], detail=False, serializer_class=CategorySelectionSerializer)
|
||||||
|
def set_categories(self, request, *args, **kwargs):
|
||||||
|
up, _ = UserPreferences.objects.get_or_create(user=request.user)
|
||||||
|
up.preferred_categories = request.data['categories']
|
||||||
|
up.save()
|
||||||
|
return Response(status=200)
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
# Generated by Django 4.2.1 on 2023-05-27 10:21
|
||||||
|
|
||||||
|
import django.contrib.postgres.fields
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("recomendations", "0007_nearesteventtorestaurant"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="userpreferences",
|
||||||
|
name="preferred_categories",
|
||||||
|
field=django.contrib.postgres.fields.ArrayField(
|
||||||
|
base_field=models.CharField(max_length=100),
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
size=None,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="userpreferences",
|
||||||
|
name="preferred_stars",
|
||||||
|
field=django.contrib.postgres.fields.ArrayField(
|
||||||
|
base_field=models.IntegerField(), blank=True, null=True, size=None
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
|
@ -1,6 +1,7 @@
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from passfinder.users.models import User
|
from passfinder.users.models import User
|
||||||
from passfinder.events.models import Event, Hotel, Restaurant
|
from passfinder.events.models import Event, Hotel, Restaurant
|
||||||
|
from django.contrib.postgres.fields import ArrayField
|
||||||
|
|
||||||
|
|
||||||
class UserPreferences(models.Model):
|
class UserPreferences(models.Model):
|
||||||
|
@ -21,6 +22,9 @@ class UserPreferences(models.Model):
|
||||||
prefferred_museums = models.ManyToManyField(Event, related_name='preffered_users_museums')
|
prefferred_museums = models.ManyToManyField(Event, related_name='preffered_users_museums')
|
||||||
unprefferred_museums = models.ManyToManyField(Event, related_name='unpreffered_users_museums')
|
unprefferred_museums = models.ManyToManyField(Event, related_name='unpreffered_users_museums')
|
||||||
|
|
||||||
|
preferred_categories = ArrayField(base_field=models.CharField(max_length=100), null=True, blank=True)
|
||||||
|
preferred_stars = ArrayField(base_field=models.IntegerField(), null=True, blank=True)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class NearestEvent(models.Model):
|
class NearestEvent(models.Model):
|
||||||
|
|
|
@ -266,8 +266,7 @@ def dist_func(event1: Event, event2: Event):
|
||||||
return dist
|
return dist
|
||||||
except:
|
except:
|
||||||
return 1000000
|
return 1000000
|
||||||
#return (event1.lon - event2.lon) ** 2 + (event1.lat - event2.lat) ** 2
|
return (event1.lon - event2.lon) ** 2 + (event1.lat - event2.lat) ** 2
|
||||||
# return (event1.lon - event2.lon) ** 2 + (event1.lat - event2.lat) ** 2
|
|
||||||
|
|
||||||
|
|
||||||
def generate_nearest():
|
def generate_nearest():
|
||||||
|
@ -349,6 +348,19 @@ def match_points():
|
||||||
print(i)
|
print(i)
|
||||||
|
|
||||||
|
|
||||||
|
def match_restaurants():
|
||||||
|
regions = list(City.objects.all())
|
||||||
|
|
||||||
|
for i, point in enumerate(Restaurant.objects.all()):
|
||||||
|
s_regions = list(sorted(regions.copy(), key=lambda x: dist_func(point, x)))
|
||||||
|
point.city = s_regions[0]
|
||||||
|
|
||||||
|
point.save()
|
||||||
|
if i % 10 == 0:
|
||||||
|
print(i)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def calculate_mean_metric(
|
def calculate_mean_metric(
|
||||||
favorite_events: Iterable[Event],
|
favorite_events: Iterable[Event],
|
||||||
target_event: Event,
|
target_event: Event,
|
||||||
|
@ -393,21 +405,50 @@ def calculate_favorite_metric(event: Event, user: User):
|
||||||
def get_exponential_koef(time: timedelta):
|
def get_exponential_koef(time: timedelta):
|
||||||
time = time.seconds
|
time = time.seconds
|
||||||
if time < 60 * 10:
|
if time < 60 * 10:
|
||||||
return 1
|
return 2
|
||||||
if time < 60 * 20:
|
if time < 60 * 20:
|
||||||
return 10
|
return 5
|
||||||
if time < 60 * 30:
|
if time < 60 * 30:
|
||||||
return 1000
|
return 10
|
||||||
if time < 60 * 40:
|
if time < 60 * 40:
|
||||||
return 100000
|
return 20
|
||||||
return int(1e10)
|
return int(1e10)
|
||||||
|
|
||||||
|
|
||||||
|
def get_category_similarity_coef(event, user):
|
||||||
|
up, _ = UserPreferences.objects.get_or_create(user=user)
|
||||||
|
cat = up.preferred_categories
|
||||||
|
if event.type in cat:
|
||||||
|
return 0.7
|
||||||
|
else:
|
||||||
|
return 1.2
|
||||||
|
|
||||||
|
|
||||||
def get_nearest_favorite(
|
def get_nearest_favorite(
|
||||||
events: Iterable[Event], user: User, base_event: Event, exclude_events: Iterable[Event] = [], velocity=3.0, top_k=1
|
events: Iterable[Event],
|
||||||
|
user: User,
|
||||||
|
base_event: Event,
|
||||||
|
exclude_events: Iterable[Event] = [],
|
||||||
|
velocity=3.0,
|
||||||
|
top_k=1
|
||||||
):
|
):
|
||||||
|
|
||||||
sorted_events = list(sorted(events, key=lambda event: calculate_favorite_metric(event, user) * get_exponential_koef(time_func(dist_func(event, base_event), velocity))))
|
sorted_events = list(
|
||||||
|
sorted(
|
||||||
|
filter(lambda event: event not in exclude_events, events),
|
||||||
|
key=lambda event:
|
||||||
|
calculate_favorite_metric(event, user) *
|
||||||
|
get_exponential_koef(
|
||||||
|
time_func(
|
||||||
|
dist_func(
|
||||||
|
event, base_event
|
||||||
|
),
|
||||||
|
velocity
|
||||||
|
)
|
||||||
|
) *
|
||||||
|
get_category_similarity_coef(event, user)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
if top_k == 1:
|
if top_k == 1:
|
||||||
return sorted_events[0]
|
return sorted_events[0]
|
||||||
|
@ -424,14 +465,6 @@ def time_func(km_distance: float, velocity: float):
|
||||||
return timedelta(minutes=(km_distance) / (velocity / 60))
|
return timedelta(minutes=(km_distance) / (velocity / 60))
|
||||||
|
|
||||||
|
|
||||||
def generate_route(point1: BasePoint, point2: BasePoint, velocity: float):
|
|
||||||
distance = dist_func(point1, point2)
|
|
||||||
time = time_func(distance, velocity)
|
|
||||||
|
|
||||||
|
|
||||||
def time_func(km_distance: float, velocity):
|
|
||||||
return timedelta(minutes=(km_distance) / (velocity / 60))
|
|
||||||
|
|
||||||
|
|
||||||
def generate_route(point1: BasePoint, point2: BasePoint, velocity):
|
def generate_route(point1: BasePoint, point2: BasePoint, velocity):
|
||||||
distance = dist_func(point1, point2)
|
distance = dist_func(point1, point2)
|
||||||
|
@ -470,14 +503,40 @@ def generate_multiple_tours(user: User, city: City, start_date: datetime.date, e
|
||||||
return pool.map(generate_tour, [(user, start_date, end_date, hotel) for hotel in hotels])
|
return pool.map(generate_tour, [(user, start_date, end_date, hotel) for hotel in hotels])
|
||||||
|
|
||||||
|
|
||||||
def generate_tour(user: User, city: City, start_date: datetime.date, end_date: datetime.date, avg_velocity=3.0):
|
def generate_tour(
|
||||||
|
user: User,
|
||||||
|
city: City,
|
||||||
|
start_date: datetime.date,
|
||||||
|
end_date: datetime.date,
|
||||||
|
avg_velocity=3.0,
|
||||||
|
stars=[],
|
||||||
|
hotel_type=['hotel', 'hostel', 'apartment'],
|
||||||
|
where_eat=['restaurant', 'bar', 'cafe'],
|
||||||
|
what_to_see=['attractions', 'museum', 'movie', 'concert', 'artwork', 'plays', 'shop', 'gallery', 'theme_park', 'viewpoint', 'zoo']
|
||||||
|
):
|
||||||
UserPreferences.objects.get_or_create(user=user)
|
UserPreferences.objects.get_or_create(user=user)
|
||||||
hotel = choice(list(Hotel.objects.filter(city=city)))
|
|
||||||
|
hotels_candidates = Hotel.objects.filter(city=city)
|
||||||
|
if len(hotels_candidates.filter(stars__in=stars)):
|
||||||
|
hotels_candidates = hotels_candidates.filter(stars__in=stars)
|
||||||
|
|
||||||
|
try:
|
||||||
|
hotel = choice(list(hotels_candidates))
|
||||||
|
except:
|
||||||
|
hotel = city
|
||||||
current_date = start_date
|
current_date = start_date
|
||||||
paths, points, disallowed_rest = [], [], []
|
paths, points, disallowed_rest = [], [], []
|
||||||
|
|
||||||
while current_date < end_date:
|
while current_date < end_date:
|
||||||
local_points, local_paths, local_disallowed_rest = generate_path(user, points, hotel, disallowed_rest, avg_velocity)
|
local_points, local_paths, local_disallowed_rest = generate_path(
|
||||||
|
user,
|
||||||
|
points,
|
||||||
|
hotel,
|
||||||
|
disallowed_rest,
|
||||||
|
avg_velocity,
|
||||||
|
where_eat=where_eat,
|
||||||
|
what_to_see=what_to_see
|
||||||
|
)
|
||||||
points.extend(local_points)
|
points.extend(local_points)
|
||||||
paths.append(
|
paths.append(
|
||||||
{
|
{
|
||||||
|
@ -514,22 +573,56 @@ def nearest_distance_points(point: BasePoint, user: User, velocity: float=3.0):
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def generate_path(user: User, disallowed_points: Iterable[BasePoint], hotel: Hotel, disallowed_rests: Iterable[Restaurant], avg_velocity: float):
|
def generate_path(
|
||||||
# region_events = Event.objects.filter(region=region)
|
user: User,
|
||||||
|
disallowed_points: Iterable[BasePoint],
|
||||||
|
hotel: Hotel,
|
||||||
|
disallowed_rests: Iterable[Restaurant],
|
||||||
|
avg_velocity: float,
|
||||||
|
where_eat=['restaurant', 'bar', 'cafe'],
|
||||||
|
what_to_see=['attractions', 'museum', 'movie', 'concert', 'artwork', 'plays', 'shop', 'gallery', 'theme_park', 'viewpoint', 'zoo']
|
||||||
|
):
|
||||||
|
allowed_types = [
|
||||||
|
'museum',
|
||||||
|
'attraction',
|
||||||
|
'artwork',
|
||||||
|
'shop',
|
||||||
|
'gallery',
|
||||||
|
'theme_park',
|
||||||
|
'zoo',
|
||||||
|
'other',
|
||||||
|
'viewpoint'
|
||||||
|
]
|
||||||
|
if len(set(allowed_types) & set(what_to_see)) == 0:
|
||||||
|
allowed_types = what_to_see
|
||||||
|
else:
|
||||||
|
allowed_types = list(set(allowed_types) & set(what_to_see))
|
||||||
|
print(allowed_types, hotel)
|
||||||
|
if isinstance(hotel, City):
|
||||||
|
start_points_candidate = Restaurant.objects.filter(city=hotel).filter(~Q(oid__in=disallowed_rests))
|
||||||
|
else:
|
||||||
|
start_points_candidate = NearestRestaurantToHotel.objects.filter(hotel=hotel).first().restaurants.filter(~Q(oid__in=disallowed_rests))
|
||||||
|
|
||||||
#candidates = NearestHotel.objects.get(hotel=hotel).nearest_events.all()
|
if len(start_points_candidate.filter(type__in=where_eat)):
|
||||||
allowed_types = ['museum', 'attraction']
|
start_points_candidate = start_points_candidate.filter(type__in=where_eat)
|
||||||
|
|
||||||
start_point = NearestRestaurantToHotel.objects.filter(hotel=hotel).first().restaurants.filter(~Q(oid__in=disallowed_rests)).first()
|
start_point = start_points_candidate[0]
|
||||||
disallowed_rests.append(start_point.oid)
|
disallowed_rests.append(start_point.oid)
|
||||||
candidates = list(filter(lambda x: x not in disallowed_points, hotel.nearest_hotel_rel.all().first().nearest_events.filter(type__in=allowed_types)))
|
|
||||||
#candidates = list(filter(lambda x: x.type in allowed_types, map(lambda x: x.event, start_point.nearestrestauranttoevent_set.all()[0:100])))
|
candidates = NearestEventToRestaurant.objects.get(restaurant=start_point).events.all().filter(type__in=allowed_types)
|
||||||
|
|
||||||
points = [start_point]
|
points = [start_point]
|
||||||
|
|
||||||
|
if isinstance(hotel, Hotel):
|
||||||
path = [
|
path = [
|
||||||
generate_hotel(hotel),
|
generate_hotel(hotel),
|
||||||
generate_route(start_point, hotel, avg_velocity),
|
generate_route(start_point, hotel, avg_velocity),
|
||||||
generate_restaurant(start_point)
|
generate_restaurant(start_point)
|
||||||
]
|
]
|
||||||
|
else:
|
||||||
|
path = [
|
||||||
|
generate_restaurant(start_point)
|
||||||
|
]
|
||||||
|
|
||||||
start_time = datetime.combine(datetime.now(), time(hour=10))
|
start_time = datetime.combine(datetime.now(), time(hour=10))
|
||||||
|
|
||||||
|
@ -537,32 +630,53 @@ def generate_path(user: User, disallowed_points: Iterable[BasePoint], hotel: Hot
|
||||||
|
|
||||||
while start_time.hour < 22 and start_time.day == datetime.now().day:
|
while start_time.hour < 22 and start_time.day == datetime.now().day:
|
||||||
if (start_time.hour > 14 and how_many_eat == 1) or (start_time.hour > 20 and how_many_eat == 2):
|
if (start_time.hour > 14 and how_many_eat == 1) or (start_time.hour > 20 and how_many_eat == 2):
|
||||||
point = NearestRestaurantToEvent.objects.filter(event=points[-1]).first().restaurants.filter(~Q(oid__in=disallowed_rests))[0]
|
print(points, start_time)
|
||||||
|
try:
|
||||||
|
point_candidates = NearestRestaurantToEvent.objects.filter(event=points[-1]).first().restaurants.filter(~Q(oid__in=disallowed_rests))
|
||||||
|
if len(point_candidates.filter(type__in=where_eat)):
|
||||||
|
point_candidates = point_candidates.filter(type__in=where_eat)
|
||||||
|
point = point_candidates[0]
|
||||||
|
|
||||||
disallowed_rests.append(point.oid)
|
disallowed_rests.append(point.oid)
|
||||||
points.append(point)
|
points.append(point)
|
||||||
# Переделать - сделать еще один прекалк на рестораны с точками
|
|
||||||
candidates = NearestEventToRestaurant.objects.get(restaurant=point).events.all().filter(type__in=allowed_types)
|
|
||||||
if len(candidates) < 10:
|
|
||||||
candidates = NearestEventToRestaurant.objects.get(restaurant=point).events.all()
|
|
||||||
|
|
||||||
|
candidates = NearestEventToRestaurant.objects.get(restaurant=point).events.all().filter(type__in=allowed_types)
|
||||||
|
if len(candidates) < 2:
|
||||||
|
candidates = NearestEventToRestaurant.objects.get(restaurant=point).events.all()
|
||||||
|
|
||||||
path.append(generate_restaurant(points[-1]))
|
path.append(generate_restaurant(points[-1]))
|
||||||
start_time += timedelta(seconds=path[-1]['time'])
|
start_time += timedelta(seconds=path[-1]['time'])
|
||||||
how_many_eat += 1
|
how_many_eat += 1
|
||||||
continue
|
continue
|
||||||
|
except:
|
||||||
|
return points, path, disallowed_rests
|
||||||
|
|
||||||
|
|
||||||
if start_time.hour > 17:
|
if start_time.hour > 17:
|
||||||
allowed_types = ['play', 'concert', 'movie']
|
allowed_types = [
|
||||||
|
'play',
|
||||||
|
'concert',
|
||||||
|
'movie',
|
||||||
|
'shop',
|
||||||
|
'gallery',
|
||||||
|
'theme_park',
|
||||||
|
'viewpoint'
|
||||||
|
]
|
||||||
|
if len(set(allowed_types) & set(what_to_see)) == 0:
|
||||||
|
allowed_types = what_to_see
|
||||||
|
else:
|
||||||
|
allowed_types = list(set(allowed_types) & set(what_to_see))
|
||||||
|
|
||||||
|
|
||||||
if candidates is None:
|
if candidates is None:
|
||||||
candidates = NearestEvent.objects.get(event=points[-1]).nearest.filter(type__in=allowed_types)
|
candidates = NearestEvent.objects.get(event=points[-1]).nearest.filter(type__in=allowed_types)
|
||||||
if len(candidates) < 10:
|
if len(candidates) < 2:
|
||||||
candidates = NearestEvent.objects.get(event=points[-1]).nearest.all()
|
candidates = NearestEvent.objects.get(event=points[-1]).nearest.all()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
points.append(get_nearest_favorite(candidates, user, points[-1], points + disallowed_points))
|
points.append(get_nearest_favorite(candidates, user, points[-1], points + disallowed_points))
|
||||||
|
|
||||||
except AttributeError:
|
except:
|
||||||
points.append(get_nearest_favorite(candidates, user, points[-1], points))
|
points.append(get_nearest_favorite(candidates, user, points[-1], points))
|
||||||
|
|
||||||
transition_route = generate_route(points[-1], points[-2], avg_velocity)
|
transition_route = generate_route(points[-1], points[-2], avg_velocity)
|
||||||
|
@ -576,15 +690,6 @@ def generate_path(user: User, disallowed_points: Iterable[BasePoint], hotel: Hot
|
||||||
return points, path, disallowed_rests
|
return points, path, disallowed_rests
|
||||||
|
|
||||||
|
|
||||||
def calculate_distance(sample1: Event, samples: Iterable[Event], model: AnnoyIndex, rev_mapping):
|
|
||||||
metrics = []
|
|
||||||
|
|
||||||
for sample in samples:
|
|
||||||
metrics.append(model.get_distance(rev_mapping[sample1.oid], rev_mapping[sample.oid]))
|
|
||||||
|
|
||||||
return sum(metrics) / len(metrics)
|
|
||||||
|
|
||||||
|
|
||||||
def calculate_distance(
|
def calculate_distance(
|
||||||
sample1: Event, samples: Iterable[Event], model: AnnoyIndex, rev_mapping
|
sample1: Event, samples: Iterable[Event], model: AnnoyIndex, rev_mapping
|
||||||
):
|
):
|
||||||
|
@ -627,11 +732,6 @@ def get_onboarding_hotels(stars=Iterable[int]):
|
||||||
|
|
||||||
|
|
||||||
def generate_points_path(user: User, points: Iterable[Event], velocity=3.0):
|
def generate_points_path(user: User, points: Iterable[Event], velocity=3.0):
|
||||||
"""
|
|
||||||
Дописать
|
|
||||||
1) генерить маршруты от многих точек (не только по 2) (salesman problem)
|
|
||||||
2) Если в маршруте до 7 точек - добавлять похожие пока не станет 7 точек
|
|
||||||
"""
|
|
||||||
if len(points) < 7:
|
if len(points) < 7:
|
||||||
candidates = NearestEvent.objects.get(event=points[0]).nearest.all()
|
candidates = NearestEvent.objects.get(event=points[0]).nearest.all()
|
||||||
points.extend(list(get_nearest_favorite(candidates, user, points[0], [], velocity, 7-len(points))))
|
points.extend(list(get_nearest_favorite(candidates, user, points[0], [], velocity, 7-len(points))))
|
||||||
|
@ -663,3 +763,114 @@ def generate_points_path(user: User, points: Iterable[Event], velocity=3.0):
|
||||||
visited_points.append(pt)
|
visited_points.append(pt)
|
||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
def flat_list(lst):
|
||||||
|
res = []
|
||||||
|
for i in lst:
|
||||||
|
res.extend(i)
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
def range_candidates(candidates, user, favorite_events):
|
||||||
|
model_mappings = {
|
||||||
|
'attraction': [attracion_model, rev_attraction_mapping],
|
||||||
|
'museum': [mus_model, rev_mus_mapping],
|
||||||
|
'movie': [cinema_model, rev_cinema_mapping],
|
||||||
|
'concert': [concert_model, rev_concert_mapping],
|
||||||
|
'plays': [plays_model, rev_plays_mapping]
|
||||||
|
}
|
||||||
|
|
||||||
|
if candidates[0].type in ['attraction', 'museum', 'movie', 'concert', 'plays']:
|
||||||
|
candidates = sorted(
|
||||||
|
candidates,
|
||||||
|
key=lambda cand: calculate_mean_metric(
|
||||||
|
favorite_events,
|
||||||
|
cand,
|
||||||
|
*model_mappings[cand.type]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return candidates[0:10]
|
||||||
|
return sample(candidates, 10)
|
||||||
|
|
||||||
|
|
||||||
|
def get_personal_recomendations(user):
|
||||||
|
up, _ = UserPreferences.objects.get_or_create(user=user)
|
||||||
|
candidates_generate_strategy = {
|
||||||
|
'plays': [lambda pref: flat_list(
|
||||||
|
list(
|
||||||
|
map(
|
||||||
|
lambda cand: nearest_plays(
|
||||||
|
cand, 30
|
||||||
|
),
|
||||||
|
pref.preffered_plays.all()
|
||||||
|
)
|
||||||
|
),
|
||||||
|
), lambda pref: pref.preffered_plays.all()],
|
||||||
|
'movie': [lambda pref: flat_list(
|
||||||
|
list(
|
||||||
|
map(
|
||||||
|
lambda cand: nearest_movie(
|
||||||
|
cand, 30
|
||||||
|
),
|
||||||
|
pref.preffered_movies.all()
|
||||||
|
)
|
||||||
|
),
|
||||||
|
), lambda pref: pref.preffered_movies.all()],
|
||||||
|
'concert': [lambda pref: flat_list(
|
||||||
|
list(
|
||||||
|
map(
|
||||||
|
lambda cand: nearest_concert(
|
||||||
|
cand, 30
|
||||||
|
),
|
||||||
|
pref.preferred_concerts.all()
|
||||||
|
)
|
||||||
|
),
|
||||||
|
), lambda pref: pref.preferred_concerts.all()],
|
||||||
|
'attractions': [lambda pref: flat_list(
|
||||||
|
list(
|
||||||
|
map(
|
||||||
|
lambda cand: nearest_attraction(
|
||||||
|
cand, 30
|
||||||
|
),
|
||||||
|
pref.prefferred_attractions.all()
|
||||||
|
)
|
||||||
|
),
|
||||||
|
), lambda pref: pref.prefferred_attractions.all()],
|
||||||
|
'museum': [lambda pref: flat_list(
|
||||||
|
list(
|
||||||
|
map(
|
||||||
|
lambda cand: nearest_mus(
|
||||||
|
cand, 30
|
||||||
|
),
|
||||||
|
pref.prefferred_museums.all()
|
||||||
|
)
|
||||||
|
),
|
||||||
|
), lambda pref: pref.prefferred_museums.all()],
|
||||||
|
'shop': [lambda pref: sample(list(Event.objects.filter(type='shop')), 10), lambda x: []],
|
||||||
|
'gallery': [lambda pref: sample(list(Event.objects.filter(type='gallery')), 10), lambda x: []],
|
||||||
|
'theme_park': [lambda pref: sample(list(Event.objects.filter(type='theme_park')), 10), lambda x: []],
|
||||||
|
'viewpoint': [lambda pref: sample(list(Event.objects.filter(type='viewpoint')), 10), lambda x: []],
|
||||||
|
'zoo': [lambda pref: sample(list(Event.objects.filter(type='zoo')), 10), lambda x: []],
|
||||||
|
}
|
||||||
|
|
||||||
|
res = []
|
||||||
|
for category_candidate in up.preferred_categories:
|
||||||
|
candidates = candidates_generate_strategy[category_candidate][0](up)
|
||||||
|
ranged = range_candidates(
|
||||||
|
candidates,
|
||||||
|
user,
|
||||||
|
candidates_generate_strategy[category_candidate][1](up)
|
||||||
|
)
|
||||||
|
res.append(
|
||||||
|
{
|
||||||
|
'category': category_candidate,
|
||||||
|
'events': list(
|
||||||
|
map(
|
||||||
|
lambda x: ObjectRouteSerializer(x).data,
|
||||||
|
ranged
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return res
|
||||||
|
|
Loading…
Reference in New Issue
Block a user