Добавил геофильтры. Теперь нужен рефакторинг.

This commit is contained in:
2025-11-17 17:44:24 +03:00
parent b889fb29a3
commit c0f2f16303
7 changed files with 385 additions and 2 deletions

View File

@@ -18,6 +18,7 @@ from .data_import import (
ProcessKubsatView,
)
from .api import (
GeoPointsAPIView,
GetLocationsView,
LyngsatDataAPIView,
SatelliteDataAPIView,
@@ -70,6 +71,7 @@ __all__ = [
'LinkVchSigmaView',
'ProcessKubsatView',
# API
'GeoPointsAPIView',
'GetLocationsView',
'LyngsatDataAPIView',
'SatelliteDataAPIView',

View File

@@ -472,6 +472,52 @@ class TransponderDataAPIView(LoginRequiredMixin, View):
return JsonResponse({'error': str(e)}, status=500)
class GeoPointsAPIView(LoginRequiredMixin, View):
"""API endpoint for getting all geo points for polygon filter visualization."""
def get(self, request):
from ..models import Geo
try:
# Limit to reasonable number of points to avoid performance issues
limit = int(request.GET.get('limit', 10000))
limit = min(limit, 50000) # Max 50k points
# Get all Geo objects with coordinates
geo_objs = Geo.objects.filter(
coords__isnull=False
).select_related(
'objitem',
'objitem__source'
)[:limit]
points = []
for geo_obj in geo_objs:
if not geo_obj.coords:
continue
# Get source_id if available
source_id = None
if hasattr(geo_obj, 'objitem') and geo_obj.objitem:
if hasattr(geo_obj.objitem, 'source') and geo_obj.objitem.source:
source_id = geo_obj.objitem.source.id
points.append({
'id': geo_obj.id,
'lat': geo_obj.coords.y,
'lng': geo_obj.coords.x,
'source_id': source_id or '-'
})
return JsonResponse({
'points': points,
'total': len(points),
'limited': len(points) >= limit
})
except Exception as e:
return JsonResponse({'error': str(e)}, status=500)
class SatelliteDataAPIView(LoginRequiredMixin, View):
"""API endpoint for getting Satellite data."""

View File

@@ -126,6 +126,7 @@ class ShowSourcesMapView(LoginRequiredMixin, View):
"""View for displaying selected sources on map."""
def get(self, request):
import json
from ..models import Source
ids = request.GET.get("ids", "")
@@ -168,8 +169,18 @@ class ShowSourcesMapView(LoginRequiredMixin, View):
else:
return redirect("mainapp:home")
# Get polygon filter from URL if present
polygon_coords_str = request.GET.get("polygon", "").strip()
polygon_coords = None
if polygon_coords_str:
try:
polygon_coords = json.loads(polygon_coords_str)
except (json.JSONDecodeError, ValueError, TypeError):
polygon_coords = None
context = {
"groups": groups,
"polygon_coords": json.dumps(polygon_coords) if polygon_coords else None,
}
return render(request, "mainapp/source_map.html", context)

View File

@@ -1,10 +1,12 @@
"""
Source related views.
"""
import json
from datetime import datetime
from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin, UserPassesTestMixin
from django.contrib.gis.geos import Point, Polygon as GEOSPolygon
from django.core.paginator import Paginator
from django.db.models import Count, Q
from django.http import JsonResponse
@@ -62,6 +64,23 @@ class SourceListView(LoginRequiredMixin, View):
snr_min = request.GET.get("snr_min", "").strip()
snr_max = request.GET.get("snr_max", "").strip()
# Get polygon filter
polygon_coords_str = request.GET.get("polygon", "").strip()
polygon_coords = None
polygon_geom = None
if polygon_coords_str:
try:
polygon_coords = json.loads(polygon_coords_str)
if polygon_coords and len(polygon_coords) >= 4:
# Create GEOS Polygon from coordinates
# Coordinates are in [lng, lat] format
polygon_geom = GEOSPolygon(polygon_coords, srid=4326)
except (json.JSONDecodeError, ValueError, TypeError) as e:
# Invalid polygon data, ignore
polygon_coords = None
polygon_geom = None
# Get all satellites for filter
satellites = (
Satellite.objects.filter(parameters__objitem__source__isnull=False)
@@ -210,6 +229,11 @@ class SourceListView(LoginRequiredMixin, View):
objitem_filter_q &= Q(source_objitems__geo_obj__mirrors__id__in=selected_mirrors)
has_objitem_filter = True
# Add polygon filter
if polygon_geom:
objitem_filter_q &= Q(source_objitems__geo_obj__coords__within=polygon_geom)
has_objitem_filter = True
# Get all Source objects with query optimization
# Using annotate to count ObjItems efficiently (single query with GROUP BY)
# Using prefetch_related for reverse ForeignKey relationships to avoid N+1 queries
@@ -443,6 +467,12 @@ class SourceListView(LoginRequiredMixin, View):
source_objitems__geo_obj__mirrors__id__in=selected_mirrors
).distinct()
# Filter by polygon
if polygon_geom:
sources = sources.filter(
source_objitems__geo_obj__coords__within=polygon_geom
).distinct()
# Apply sorting
valid_sort_fields = {
"id": "id",
@@ -540,6 +570,8 @@ class SourceListView(LoginRequiredMixin, View):
objitems_to_display = objitems_to_display.filter(geo_obj__mirrors__id__in=selected_mirrors)
if search_by_name:
objitems_to_display = objitems_to_display.filter(name__icontains=search_query)
if polygon_geom:
objitems_to_display = objitems_to_display.filter(geo_obj__coords__within=polygon_geom)
# Use annotated count (consistent with filtering)
objitem_count = source.objitem_count
@@ -652,6 +684,7 @@ class SourceListView(LoginRequiredMixin, View):
int(x) if isinstance(x, str) else x for x in selected_mirrors if (isinstance(x, int) or (isinstance(x, str) and x.isdigit()))
],
'object_infos': object_infos,
'polygon_coords': json.dumps(polygon_coords) if polygon_coords else None,
'full_width_page': True,
}