Доделал страницу со всеми объектами

This commit is contained in:
2025-11-01 16:39:06 +03:00
parent c8a951eac6
commit 439ca6407f
2089 changed files with 13968 additions and 142 deletions

View File

@@ -6,6 +6,7 @@ from django.contrib.admin.views.decorators import staff_member_required
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views import View
from django.db.models import OuterRef, Subquery
from django.views.generic import TemplateView, FormView, UpdateView, DeleteView, CreateView
from django.contrib.auth.mixins import UserPassesTestMixin, LoginRequiredMixin
from django.contrib.auth import logout
@@ -34,7 +35,7 @@ from .forms import (
ParameterForm,
GeoForm
)
from .models import ObjItem
from .models import ObjItem, Modulation, Polarization
from .clusters import get_clusters
from io import BytesIO
from datetime import datetime
@@ -320,13 +321,12 @@ from django.contrib.auth.mixins import LoginRequiredMixin
class ObjItemListView(LoginRequiredMixin, View):
def get(self, request):
satellites = Satellite.objects.filter(parameters__objitems__isnull=False).distinct().order_by('name')
# Get selected satellite from query parameters
selected_sat_id = request.GET.get('satellite_id')
page_number = request.GET.get('page', 1)
items_per_page = request.GET.get('items_per_page', '50')
# Get filter parameters
sort_param = request.GET.get('sort', '')
freq_min = request.GET.get('freq_min')
freq_max = request.GET.get('freq_max')
range_min = request.GET.get('range_min')
@@ -341,28 +341,23 @@ class ObjItemListView(LoginRequiredMixin, View):
selected_satellites = request.GET.getlist('satellite_id')
has_kupsat = request.GET.get('has_kupsat')
has_valid = request.GET.get('has_valid')
try:
items_per_page = int(items_per_page)
except ValueError:
items_per_page = 50
# Only filter objects by selected satellite if provided (no data shown by default)
objects = ObjItem.objects.none() # Initially empty
objects = ObjItem.objects.none()
if selected_satellites or selected_sat_id:
# Handle single satellite from old parameter or multiple from new parameter
if selected_sat_id and not selected_satellites:
# For backward compatibility - if only single satellite parameter is provided
try:
selected_sat_id_single = int(selected_sat_id)
selected_satellites = [selected_sat_id_single]
except ValueError:
selected_satellites = []
# Start with the basic filter if any satellites are selected
if selected_satellites:
# Start with the basic filter - optimized with prefetch_related for all related objects
objects = ObjItem.objects.select_related(
'geo_obj',
'updated_by__user',
@@ -374,7 +369,6 @@ class ObjItemListView(LoginRequiredMixin, View):
'parameters_obj__standard'
).filter(parameters_obj__id_satellite_id__in=selected_satellites)
else:
# If no satellites are selected, start with all objects
objects = ObjItem.objects.select_related(
'geo_obj',
'updated_by__user',
@@ -385,9 +379,7 @@ class ObjItemListView(LoginRequiredMixin, View):
'parameters_obj__modulation',
'parameters_obj__standard'
)
# Apply additional filters
# Frequency filter
if freq_min is not None and freq_min.strip() != '':
try:
freq_min_val = float(freq_min)
@@ -400,8 +392,7 @@ class ObjItemListView(LoginRequiredMixin, View):
objects = objects.filter(parameters_obj__frequency__lte=freq_max_val)
except ValueError:
pass
# Range filter
if range_min is not None and range_min.strip() != '':
try:
range_min_val = float(range_min)
@@ -414,8 +405,7 @@ class ObjItemListView(LoginRequiredMixin, View):
objects = objects.filter(parameters_obj__freq_range__lte=range_max_val)
except ValueError:
pass
# SNR filter
if snr_min is not None and snr_min.strip() != '':
try:
snr_min_val = float(snr_min)
@@ -428,8 +418,7 @@ class ObjItemListView(LoginRequiredMixin, View):
objects = objects.filter(parameters_obj__snr__lte=snr_max_val)
except ValueError:
pass
# Symbol rate filter
if bod_min is not None and bod_min.strip() != '':
try:
bod_min_val = float(bod_min)
@@ -442,72 +431,110 @@ class ObjItemListView(LoginRequiredMixin, View):
objects = objects.filter(parameters_obj__bod_velocity__lte=bod_max_val)
except ValueError:
pass
# Modulation filter
if selected_modulations:
objects = objects.filter(parameters_obj__modulation__id__in=selected_modulations)
# Polarization filter
if selected_polarizations:
objects = objects.filter(parameters_obj__polarization__id__in=selected_polarizations)
# Kupsat coords filter
if has_kupsat == '1': # has coords
if has_kupsat == '1':
objects = objects.filter(geo_obj__coords_kupsat__isnull=False)
elif has_kupsat == '0': # no coords
elif has_kupsat == '0':
objects = objects.filter(geo_obj__coords_kupsat__isnull=True)
# Valid coords filter
if has_valid == '1': # has coords
if has_valid == '1':
objects = objects.filter(geo_obj__coords_valid__isnull=False)
elif has_valid == '0': # no coords
elif has_valid == '0':
objects = objects.filter(geo_obj__coords_valid__isnull=True)
# Add search functionality - search only in name and location fields to avoid spatial lookup errors
if search_query:
search_query = search_query.strip()
if search_query:
# Search in name and location fields to match displayed text
objects = objects.filter(
models.Q(name__icontains=search_query) |
models.Q(geo_obj__location__icontains=search_query)
)
else:
selected_sat_id = None
# Add pagination
first_param_freq_subq = self.get_first_param_subquery('frequency')
first_param_range_subq = self.get_first_param_subquery('freq_range')
first_param_snr_subq = self.get_first_param_subquery('snr')
first_param_bod_subq = self.get_first_param_subquery('bod_velocity')
first_param_sat_name_subq = self.get_first_param_subquery('id_satellite__name')
first_param_pol_name_subq = self.get_first_param_subquery('polarization__name')
first_param_mod_name_subq = self.get_first_param_subquery('modulation__name')
objects = objects.annotate(
first_param_freq=Subquery(first_param_freq_subq),
first_param_range=Subquery(first_param_range_subq),
first_param_snr=Subquery(first_param_snr_subq),
first_param_bod=Subquery(first_param_bod_subq),
first_param_sat_name=Subquery(first_param_sat_name_subq),
first_param_pol_name=Subquery(first_param_pol_name_subq),
first_param_mod_name=Subquery(first_param_mod_name_subq),
)
valid_sort_fields = {
'name': 'name',
'-name': '-name',
'updated_at': 'updated_at',
'-updated_at': '-updated_at',
'created_at': 'created_at',
'-created_at': '-created_at',
'updated_by': 'updated_by__user__username',
'-updated_by': '-updated_by__user__username',
'created_by': 'created_by__user__username',
'-created_by': '-created_by__user__username',
'geo_timestamp': 'geo_obj__timestamp',
'-geo_timestamp': '-geo_obj__timestamp',
'frequency': 'first_param_freq',
'-frequency': '-first_param_freq',
'freq_range': 'first_param_range',
'-freq_range': '-first_param_range',
'snr': 'first_param_snr',
'-snr': '-first_param_snr',
'bod_velocity': 'first_param_bod',
'-bod_velocity': '-first_param_bod',
'satellite': 'first_param_sat_name',
'-satellite': '-first_param_sat_name',
'polarization': 'first_param_pol_name',
'-polarization': '-first_param_pol_name',
'modulation': 'first_param_mod_name',
'-modulation': '-first_param_mod_name',
}
if sort_param in valid_sort_fields:
objects = objects.order_by(valid_sort_fields[sort_param])
paginator = Paginator(objects, items_per_page)
page_obj = paginator.get_page(page_number)
# Prepare the data to include calculated fields for the template
processed_objects = []
for obj in page_obj:
# Get the first parameter using the prefetched relation to avoid additional queries
param = None
if hasattr(obj, 'parameters_obj') and obj.parameters_obj.all():
# Get parameters from the prefetched queryset without triggering new query
param_list = list(obj.parameters_obj.all())
if param_list:
param = param_list[0] # Get first parameter without additional query
# Process geo coordinates
param = param_list[0]
geo_coords = "-"
kupsat_coords = "-"
valid_coords = "-"
distance_geo_kup = "-"
distance_geo_valid = "-"
distance_kup_valid = "-"
if obj.geo_obj:
# Format geo coordinates
geo_timestamp = obj.geo_obj.timestamp
if obj.geo_obj.coords:
longitude = obj.geo_obj.coords.coords[0]
latitude = obj.geo_obj.coords.coords[1]
lon = f"{longitude}E" if longitude > 0 else f"{abs(longitude)}W"
lat = f"{latitude}N" if latitude > 0 else f"{abs(latitude)}S"
geo_coords = f"{lat} {lon}"
# Format kupsat coordinates
if obj.geo_obj.coords_kupsat:
longitude = obj.geo_obj.coords_kupsat.coords[0]
latitude = obj.geo_obj.coords_kupsat.coords[1]
@@ -516,8 +543,7 @@ class ObjItemListView(LoginRequiredMixin, View):
kupsat_coords = f"{lat} {lon}"
elif obj.geo_obj.coords_kupsat is not None:
kupsat_coords = "-"
# Format valid coordinates
if obj.geo_obj.coords_valid:
longitude = obj.geo_obj.coords_valid.coords[0]
latitude = obj.geo_obj.coords_valid.coords[1]
@@ -526,18 +552,16 @@ class ObjItemListView(LoginRequiredMixin, View):
valid_coords = f"{lat} {lon}"
elif obj.geo_obj.coords_valid is not None:
valid_coords = "-"
# Format distances
if obj.geo_obj.distance_coords_kup is not None:
distance_geo_kup = f"{obj.geo_obj.distance_coords_kup:.3f}"
if obj.geo_obj.distance_coords_valid is not None:
distance_geo_valid = f"{obj.geo_obj.distance_coords_valid:.3f}"
if obj.geo_obj.distance_kup_valid is not None:
distance_kup_valid = f"{obj.geo_obj.distance_kup_valid:.3f}"
# Extract related object data to avoid additional queries in template
satellite_name = "-"
frequency = "-"
freq_range = "-"
@@ -545,26 +569,22 @@ class ObjItemListView(LoginRequiredMixin, View):
bod_velocity = "-"
modulation_name = "-"
snr = "-"
if param:
# Get satellite data directly to avoid additional query
if hasattr(param, 'id_satellite') and param.id_satellite:
satellite_name = param.id_satellite.name if hasattr(param.id_satellite, 'name') else "-"
# Get parameter values directly
frequency = f"{param.frequency:.3f}" if param.frequency is not None else "-"
freq_range = f"{param.freq_range:.3f}" if param.freq_range is not None else "-"
bod_velocity = f"{param.bod_velocity:.0f}" if param.bod_velocity is not None else "-"
snr = f"{param.snr:.0f}" if param.snr is not None else "-"
# Get polarization name directly to avoid additional query
if hasattr(param, 'polarization') and param.polarization:
polarization_name = param.polarization.name if hasattr(param.polarization, 'name') else "-"
# Get modulation name directly to avoid additional query
if hasattr(param, 'modulation') and param.modulation:
modulation_name = param.modulation.name if hasattr(param.modulation, 'name') else "-"
processed_objects.append({
'id': obj.id,
'name': obj.name or "-",
@@ -575,6 +595,7 @@ class ObjItemListView(LoginRequiredMixin, View):
'bod_velocity': bod_velocity,
'modulation': modulation_name,
'snr': snr,
'geo_timestamp': geo_timestamp,
'geo_coords': geo_coords,
'kupsat_coords': kupsat_coords,
'valid_coords': valid_coords,
@@ -584,12 +605,10 @@ class ObjItemListView(LoginRequiredMixin, View):
'updated_by': obj.updated_by if obj.updated_by else '-',
'obj': obj
})
# Get all modulations and polarizations for filter dropdowns
from .models import Modulation, Polarization
modulations = Modulation.objects.all()
polarizations = Polarization.objects.all()
context = {
'satellites': satellites,
'selected_satellite_id': selected_sat_id,
@@ -597,7 +616,6 @@ class ObjItemListView(LoginRequiredMixin, View):
'processed_objects': processed_objects,
'items_per_page': items_per_page,
'available_items_per_page': [50, 100, 500, 1000],
# Filter values
'freq_min': freq_min,
'freq_max': freq_max,
'range_min': range_min,
@@ -612,14 +630,18 @@ class ObjItemListView(LoginRequiredMixin, View):
'selected_satellites': [int(x) for x in selected_satellites if x.isdigit()],
'has_kupsat': has_kupsat,
'has_valid': has_valid,
# For filter dropdowns
'modulations': modulations,
'polarizations': polarizations,
# Enable full width layout
'full_width_page': True,
'sort': sort_param,
}
return render(request, 'mainapp/objitem_list.html', context)
def get_first_param_subquery(self, field_name):
return Parameter.objects.filter(
objitems=OuterRef('pk')
).order_by('id').values(field_name)[:1]
class ObjItemUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
model = ObjItem
@@ -632,14 +654,10 @@ class ObjItemUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
# Добавляем контекст для карты
context['LEAFLET_CONFIG'] = {
'DEFAULT_CENTER': (55.75, 37.62),
'DEFAULT_ZOOM': 5,
}
# Остальной контекст остается без изменений
ParameterFormSet = modelformset_factory(
Parameter,
form=ParameterForm,
@@ -703,19 +721,19 @@ class ObjItemUpdateView(LoginRequiredMixin, UserPassesTestMixin, UpdateView):
geo_longitude = self.request.POST.get('geo_longitude')
geo_latitude = self.request.POST.get('geo_latitude')
if geo_longitude and geo_latitude:
geo_instance.coords = Point(float(geo_longitude), float(geo_latitude))
geo_instance.coords = Point(float(geo_longitude), float(geo_latitude), srid=4326)
# Обрабатываем координаты Кубсата
kupsat_longitude = self.request.POST.get('kupsat_longitude')
kupsat_latitude = self.request.POST.get('kupsat_latitude')
if kupsat_longitude and kupsat_latitude:
geo_instance.coords_kupsat = Point(float(kupsat_longitude), float(kupsat_latitude))
geo_instance.coords_kupsat = Point(float(kupsat_longitude), float(kupsat_latitude), srid=4326)
# Обрабатываем координаты оперативников
valid_longitude = self.request.POST.get('valid_longitude')
valid_latitude = self.request.POST.get('valid_latitude')
if valid_longitude and valid_latitude:
geo_instance.coords_valid = Point(float(valid_longitude), float(valid_latitude))
geo_instance.coords_valid = Point(float(valid_longitude), float(valid_latitude), srid=4326)
# Обрабатываем дату/время
timestamp_date = self.request.POST.get('timestamp_date')
@@ -788,19 +806,19 @@ class ObjItemCreateView(LoginRequiredMixin, UserPassesTestMixin, CreateView):
geo_longitude = self.request.POST.get('geo_longitude')
geo_latitude = self.request.POST.get('geo_latitude')
if geo_longitude and geo_latitude:
geo_instance.coords = Point(float(geo_longitude), float(geo_latitude))
geo_instance.coords = Point(float(geo_longitude), float(geo_latitude), srid=4326)
# Обрабатываем координаты Кубсата
kupsat_longitude = self.request.POST.get('kupsat_longitude')
kupsat_latitude = self.request.POST.get('kupsat_latitude')
if kupsat_longitude and kupsat_latitude:
geo_instance.coords_kupsat = Point(float(kupsat_longitude), float(kupsat_latitude))
geo_instance.coords_kupsat = Point(float(kupsat_longitude), float(kupsat_latitude), srid=4326)
# Обрабатываем координаты оперативников
valid_longitude = self.request.POST.get('valid_longitude')
valid_latitude = self.request.POST.get('valid_latitude')
if valid_longitude and valid_latitude:
geo_instance.coords_valid = Point(float(valid_longitude), float(valid_latitude))
geo_instance.coords_valid = Point(float(valid_longitude), float(valid_latitude), srid=4326)
# Обрабатываем дату/время
timestamp_date = self.request.POST.get('timestamp_date')