Files
dbstorage/dbapp/mapsapp/views.py

170 lines
6.7 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.

# Standard library imports
from typing import Any, Dict
# Django imports
from django.contrib.auth.mixins import LoginRequiredMixin
from django.http import HttpResponse, HttpResponseNotFound, JsonResponse
from django.utils.decorators import method_decorator
from django.views import View
from django.views.decorators.cache import cache_page
from django.views.decorators.http import require_GET
from django.views.generic import TemplateView
# Third-party imports
import requests
# Local imports
from mainapp.models import Satellite
from .models import Transponders
from .utils import get_band_names
class CesiumMapView(LoginRequiredMixin, TemplateView):
"""
Представление для отображения 3D карты с использованием Cesium.
Отображает спутники и их зоны покрытия на интерактивной 3D карте.
"""
template_name = "mapsapp/map3d.html"
def get_context_data(self, **kwargs: Any) -> Dict[str, Any]:
context = super().get_context_data(**kwargs)
# Оптимизированный запрос - загружаем только необходимые поля
# Фильтруем спутники, у которых есть параметры с привязанными объектами
context["sats"] = (
Satellite.objects.filter(parameters__objitem__isnull=False)
.distinct()
.only("id", "name")
.order_by("name")
)
return context
class GetFootprintsView(LoginRequiredMixin, View):
"""
API для получения зон покрытия (footprints) спутника.
Возвращает список названий зон покрытия для указанного спутника.
"""
def get(self, request, sat_id):
try:
# Оптимизированный запрос - загружаем только поле name
sat_name = Satellite.objects.only("name").get(id=sat_id).name
footprint_names = get_band_names(sat_name)
return JsonResponse(footprint_names, safe=False)
except Satellite.DoesNotExist:
return JsonResponse({"error": "Спутник не найден"}, status=404)
except Exception as e:
return JsonResponse({"error": str(e)}, status=500)
class TileProxyView(View):
"""
Прокси для загрузки тайлов карты покрытия спутников.
Кэширует тайлы на 7 дней для улучшения производительности.
"""
# Константы
TILE_BASE_URL = "https://static.satbeams.com/tiles"
CACHE_DURATION = 60 * 60 * 24 * 7 # 7 дней
REQUEST_TIMEOUT = 10 # секунд
@method_decorator(require_GET)
@method_decorator(cache_page(CACHE_DURATION))
def dispatch(self, *args, **kwargs):
return super().dispatch(*args, **kwargs)
def get(self, request, footprint_name, z, x, y):
# Валидация имени footprint
if not footprint_name.replace("-", "").replace("_", "").isalnum():
return HttpResponse("Invalid footprint name", status=400)
url = f"{self.TILE_BASE_URL}/{footprint_name}/{z}/{x}/{y}.png"
try:
resp = requests.get(url, timeout=self.REQUEST_TIMEOUT, verify=r'/home/vesemir/DataStorage/cert.pem')
if resp.status_code == 200:
response = HttpResponse(resp.content, content_type="image/png")
response["Access-Control-Allow-Origin"] = "*"
response["Cache-Control"] = f"public, max-age={self.CACHE_DURATION}"
return response
else:
return HttpResponseNotFound("Tile not found")
except requests.Timeout:
return HttpResponse("Request timeout", status=504)
except requests.RequestException as e:
return HttpResponse(f"Proxy error: {e}", status=500)
class LeafletMapView(LoginRequiredMixin, TemplateView):
"""
Представление для отображения 2D карты с использованием Leaflet.
Отображает спутники и транспондеры на интерактивной 2D карте.
"""
template_name = "mapsapp/map2d.html"
def get_context_data(self, **kwargs: Any) -> Dict[str, Any]:
context = super().get_context_data(**kwargs)
# Оптимизированные запросы - загружаем только необходимые поля
# Фильтруем спутники, у которых есть параметры с привязанными объектами
context["sats"] = (
Satellite.objects.filter(parameters__objitem__isnull=False)
.distinct()
.only("id", "name")
.order_by("name")
)
context["trans"] = Transponders.objects.select_related(
"sat_id", "polarization"
).only(
"id",
"name",
"sat_id__name",
"polarization__name",
"downlink",
"frequency_range",
"zone_name",
)
return context
class GetTransponderOnSatIdView(LoginRequiredMixin, View):
"""
API для получения транспондеров спутника.
Возвращает список транспондеров для указанного спутника с оптимизированными запросами.
"""
def get(self, request, sat_id):
# Оптимизированный запрос с select_related и only
trans = (
Transponders.objects.filter(sat_id=sat_id)
.select_related("polarization")
.only(
"name", "downlink", "frequency_range", "zone_name", "polarization__name"
)
)
if not trans.exists():
return JsonResponse({"error": "Объектов не найдено"}, status=404)
# Используем list comprehension для лучшей производительности
output = [
{
"name": tran.name,
"frequency": tran.downlink,
"frequency_range": tran.frequency_range,
"zone_name": tran.zone_name,
"polarization": tran.polarization.name if tran.polarization else "-",
}
for tran in trans
]
return JsonResponse(output, safe=False)