Страница с Кубсатами

This commit is contained in:
2025-11-19 17:36:39 +03:00
parent 4d7cc9f667
commit 66e1929978
12 changed files with 1429 additions and 159 deletions

View File

@@ -8,7 +8,7 @@ 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.db.models import Count, Prefetch, Q
from django.http import JsonResponse
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
@@ -234,10 +234,109 @@ class SourceListView(LoginRequiredMixin, View):
objitem_filter_q &= Q(source_objitems__geo_obj__coords__within=polygon_geom)
has_objitem_filter = True
# Build filtered objitems queryset for prefetch
from ..models import ObjItem
filtered_objitems_qs = ObjItem.objects.select_related(
'parameter_obj',
'parameter_obj__id_satellite',
'parameter_obj__polarization',
'parameter_obj__modulation',
'parameter_obj__standard',
'geo_obj',
'lyngsat_source',
'lyngsat_source__id_satellite',
'lyngsat_source__polarization',
'lyngsat_source__modulation',
'lyngsat_source__standard',
'transponder',
'created_by',
'created_by__user',
'updated_by',
'updated_by__user',
).prefetch_related(
'geo_obj__mirrors',
)
# Apply the same filters to prefetch queryset
if search_by_name:
filtered_objitems_qs = filtered_objitems_qs.filter(name__icontains=search_query)
if geo_date_from:
try:
geo_date_from_obj = datetime.strptime(geo_date_from, "%Y-%m-%d")
filtered_objitems_qs = filtered_objitems_qs.filter(geo_obj__timestamp__gte=geo_date_from_obj)
except (ValueError, TypeError):
pass
if geo_date_to:
try:
from datetime import timedelta
geo_date_to_obj = datetime.strptime(geo_date_to, "%Y-%m-%d")
geo_date_to_obj = geo_date_to_obj + timedelta(days=1)
filtered_objitems_qs = filtered_objitems_qs.filter(geo_obj__timestamp__lt=geo_date_to_obj)
except (ValueError, TypeError):
pass
if selected_satellites:
filtered_objitems_qs = filtered_objitems_qs.filter(parameter_obj__id_satellite_id__in=selected_satellites)
if selected_polarizations:
filtered_objitems_qs = filtered_objitems_qs.filter(parameter_obj__polarization_id__in=selected_polarizations)
if selected_modulations:
filtered_objitems_qs = filtered_objitems_qs.filter(parameter_obj__modulation_id__in=selected_modulations)
if freq_min:
try:
freq_min_val = float(freq_min)
filtered_objitems_qs = filtered_objitems_qs.filter(parameter_obj__frequency__gte=freq_min_val)
except (ValueError, TypeError):
pass
if freq_max:
try:
freq_max_val = float(freq_max)
filtered_objitems_qs = filtered_objitems_qs.filter(parameter_obj__frequency__lte=freq_max_val)
except (ValueError, TypeError):
pass
if freq_range_min:
try:
freq_range_min_val = float(freq_range_min)
filtered_objitems_qs = filtered_objitems_qs.filter(parameter_obj__freq_range__gte=freq_range_min_val)
except (ValueError, TypeError):
pass
if freq_range_max:
try:
freq_range_max_val = float(freq_range_max)
filtered_objitems_qs = filtered_objitems_qs.filter(parameter_obj__freq_range__lte=freq_range_max_val)
except (ValueError, TypeError):
pass
if bod_velocity_min:
try:
bod_velocity_min_val = float(bod_velocity_min)
filtered_objitems_qs = filtered_objitems_qs.filter(parameter_obj__bod_velocity__gte=bod_velocity_min_val)
except (ValueError, TypeError):
pass
if bod_velocity_max:
try:
bod_velocity_max_val = float(bod_velocity_max)
filtered_objitems_qs = filtered_objitems_qs.filter(parameter_obj__bod_velocity__lte=bod_velocity_max_val)
except (ValueError, TypeError):
pass
if snr_min:
try:
snr_min_val = float(snr_min)
filtered_objitems_qs = filtered_objitems_qs.filter(parameter_obj__snr__gte=snr_min_val)
except (ValueError, TypeError):
pass
if snr_max:
try:
snr_max_val = float(snr_max)
filtered_objitems_qs = filtered_objitems_qs.filter(parameter_obj__snr__lte=snr_max_val)
except (ValueError, TypeError):
pass
if selected_mirrors:
filtered_objitems_qs = filtered_objitems_qs.filter(geo_obj__mirrors__id__in=selected_mirrors)
if polygon_geom:
filtered_objitems_qs = filtered_objitems_qs.filter(geo_obj__coords__within=polygon_geom)
# Get all Source objects with query optimization
# Using annotate to count ObjItems efficiently (single query with GROUP BY)
# Using select_related for ForeignKey/OneToOne relationships to avoid N+1 queries
# Using prefetch_related for reverse ForeignKey and ManyToMany relationships
# Using Prefetch with filtered queryset to avoid N+1 queries in display loop
sources = Source.objects.select_related(
'info', # ForeignKey to ObjectInfo
'created_by', # ForeignKey to CustomUser
@@ -245,25 +344,8 @@ class SourceListView(LoginRequiredMixin, View):
'updated_by', # ForeignKey to CustomUser
'updated_by__user', # OneToOne to User
).prefetch_related(
# Prefetch related objitems with their nested relationships
'source_objitems',
'source_objitems__parameter_obj',
'source_objitems__parameter_obj__id_satellite',
'source_objitems__parameter_obj__polarization',
'source_objitems__parameter_obj__modulation',
'source_objitems__parameter_obj__standard',
'source_objitems__geo_obj',
'source_objitems__geo_obj__mirrors',
'source_objitems__lyngsat_source',
'source_objitems__lyngsat_source__id_satellite',
'source_objitems__lyngsat_source__polarization',
'source_objitems__lyngsat_source__modulation',
'source_objitems__lyngsat_source__standard',
'source_objitems__transponder',
'source_objitems__created_by',
'source_objitems__created_by__user',
'source_objitems__updated_by',
'source_objitems__updated_by__user',
# Use Prefetch with filtered queryset
Prefetch('source_objitems', queryset=filtered_objitems_qs, to_attr='filtered_objitems'),
# Prefetch marks with their relationships
'marks',
'marks__created_by',
@@ -525,76 +607,8 @@ class SourceListView(LoginRequiredMixin, View):
coords_valid_str = format_coords_display(source.coords_valid)
coords_reference_str = format_coords_display(source.coords_reference)
# Filter objitems for display (to get satellites and lyngsat info)
objitems_to_display = source.source_objitems.all()
# Apply the same filters as in the count annotation
if geo_date_from:
try:
geo_date_from_obj = datetime.strptime(geo_date_from, "%Y-%m-%d")
objitems_to_display = objitems_to_display.filter(geo_obj__timestamp__gte=geo_date_from_obj)
except (ValueError, TypeError):
pass
if geo_date_to:
try:
from datetime import timedelta
geo_date_to_obj = datetime.strptime(geo_date_to, "%Y-%m-%d")
geo_date_to_obj = geo_date_to_obj + timedelta(days=1)
objitems_to_display = objitems_to_display.filter(geo_obj__timestamp__lt=geo_date_to_obj)
except (ValueError, TypeError):
pass
if selected_satellites:
objitems_to_display = objitems_to_display.filter(parameter_obj__id_satellite_id__in=selected_satellites)
if selected_polarizations:
objitems_to_display = objitems_to_display.filter(parameter_obj__polarization_id__in=selected_polarizations)
if selected_modulations:
objitems_to_display = objitems_to_display.filter(parameter_obj__modulation_id__in=selected_modulations)
if freq_min:
try:
objitems_to_display = objitems_to_display.filter(parameter_obj__frequency__gte=float(freq_min))
except (ValueError, TypeError):
pass
if freq_max:
try:
objitems_to_display = objitems_to_display.filter(parameter_obj__frequency__lte=float(freq_max))
except (ValueError, TypeError):
pass
if freq_range_min:
try:
objitems_to_display = objitems_to_display.filter(parameter_obj__freq_range__gte=float(freq_range_min))
except (ValueError, TypeError):
pass
if freq_range_max:
try:
objitems_to_display = objitems_to_display.filter(parameter_obj__freq_range__lte=float(freq_range_max))
except (ValueError, TypeError):
pass
if bod_velocity_min:
try:
objitems_to_display = objitems_to_display.filter(parameter_obj__bod_velocity__gte=float(bod_velocity_min))
except (ValueError, TypeError):
pass
if bod_velocity_max:
try:
objitems_to_display = objitems_to_display.filter(parameter_obj__bod_velocity__lte=float(bod_velocity_max))
except (ValueError, TypeError):
pass
if snr_min:
try:
objitems_to_display = objitems_to_display.filter(parameter_obj__snr__gte=float(snr_min))
except (ValueError, TypeError):
pass
if snr_max:
try:
objitems_to_display = objitems_to_display.filter(parameter_obj__snr__lte=float(snr_max))
except (ValueError, TypeError):
pass
if selected_mirrors:
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 pre-filtered objitems from Prefetch
objitems_to_display = source.filtered_objitems
# Use annotated count (consistent with filtering)
objitem_count = source.objitem_count