uchill/backend/apps/users/geo_utils.py

86 lines
3.0 KiB
Python
Raw Permalink 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.

"""
Вспомогательные функции для работы со справочниками стран, городов и часовых поясов.
Пока данные хранятся в JSON-файлах внутри приложения users.
В будущем можно перенести это в модели БД.
"""
import json
import os
from functools import lru_cache
from typing import List, Dict, Any, Optional
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
DATA_DIR = os.path.join(BASE_DIR, "geo_data")
def _load_json(filename: str) -> Any:
path = os.path.join(DATA_DIR, filename)
if not os.path.exists(path):
return []
with open(path, "r", encoding="utf-8") as f:
return json.load(f)
@lru_cache(maxsize=1)
def get_countries() -> List[Dict[str, Any]]:
"""
Получить список стран.
Формат элементов: { "code": "RU", "name": "Россия" }
"""
return _load_json("countries.json")
@lru_cache(maxsize=1)
def get_timezones() -> List[Dict[str, Any]]:
"""
Получить список часовых поясов.
Формат элементов: { "name": "Europe/Moscow", "offset": "+03:00" }
"""
return _load_json("timezones.json")
@lru_cache(maxsize=None)
def get_cities_for_country(country_code: str) -> List[Dict[str, Any]]:
"""
Получить список городов для заданной страны.
Пока реализовано только для России (RU).
Формат элементов: { "country_code": "RU", "country_name": "Россия", "city": "Москва", "timezone": "Europe/Moscow" }
"""
code = country_code.upper()
if code == "RU":
return _load_json("cities_ru.json")
# Для других стран можно добавить отдельные файлы и условия
return []
def search_cities(country: Optional[str] = None, query: Optional[str] = None) -> List[Dict[str, Any]]:
"""
Поиск городов по стране и части названия.
"""
cities: List[Dict[str, Any]] = []
if country:
# Предполагаем, что приходит код страны (RU) или название
code = country.upper()
if len(code) == 2:
cities = get_cities_for_country(code)
else:
# Ищем по названию страны в списке стран и берём по коду
for c in get_countries():
if c.get("name", "").lower().startswith(country.lower()):
cities = get_cities_for_country(c.get("code", ""))
break
else:
# Если страна не указана, возвращаем только базовый список популярных городов России
cities = get_cities_for_country("RU")
if query:
q = query.lower()
cities = [c for c in cities if q in c.get("city", "").lower()]
return cities