845 lines
34 KiB
Python
845 lines
34 KiB
Python
from django.shortcuts import render, redirect
|
||
from django.contrib import messages
|
||
from django.http import JsonResponse, HttpResponse
|
||
from django.views.decorators.http import require_GET
|
||
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
|
||
from django.forms import inlineformset_factory, modelformset_factory
|
||
from django.db import models
|
||
from django.urls import reverse_lazy
|
||
from django.contrib.gis.geos import Point
|
||
import pandas as pd
|
||
from .utils import (
|
||
fill_data_from_df,
|
||
add_satellite_list,
|
||
get_points_from_csv,
|
||
get_vch_load_from_html,
|
||
compare_and_link_vch_load,
|
||
kub_report
|
||
)
|
||
from mapsapp.utils import parse_transponders_from_json, parse_transponders_from_xml
|
||
from .forms import (
|
||
LoadExcelData,
|
||
LoadCsvData,
|
||
UploadFileForm,
|
||
VchLinkForm,
|
||
UploadVchLoad,
|
||
NewEventForm,
|
||
ObjItemForm,
|
||
ParameterForm,
|
||
GeoForm
|
||
)
|
||
from .models import ObjItem, Modulation, Polarization
|
||
from .clusters import get_clusters
|
||
from io import BytesIO
|
||
from datetime import datetime
|
||
|
||
|
||
|
||
class AddSatellitesView(LoginRequiredMixin, View):
|
||
def get(self, request):
|
||
add_satellite_list()
|
||
return redirect('home')
|
||
|
||
# class AddTranspondersView(View):
|
||
# def get(self, request):
|
||
# try:
|
||
# parse_transponders_from_json(BASE_DIR / "transponders.json")
|
||
# except FileNotFoundError:
|
||
# print("Файл не найден")
|
||
# return redirect('home')
|
||
|
||
class AddTranspondersView(LoginRequiredMixin, FormView):
|
||
template_name = 'mainapp/transponders_upload.html'
|
||
form_class = UploadFileForm
|
||
|
||
def form_valid(self, form):
|
||
uploaded_file = self.request.FILES['file']
|
||
try:
|
||
content = uploaded_file.read()
|
||
parse_transponders_from_xml(BytesIO(content))
|
||
messages.success(self.request, "Файл успешно обработан")
|
||
except ValueError as e:
|
||
messages.error(self.request, f"Ошибка при чтении таблиц: {e}")
|
||
except Exception as e:
|
||
messages.error(self.request, f"Неизвестная ошибка: {e}")
|
||
return redirect('add_trans')
|
||
|
||
def form_invalid(self, form):
|
||
messages.error(self.request, "Форма заполнена некорректно.")
|
||
return super().form_invalid(form)
|
||
|
||
from django.views.generic import View
|
||
|
||
class ActionsPageView(View):
|
||
def get(self, request):
|
||
if request.user.is_authenticated:
|
||
return render(request, 'mainapp/actions.html')
|
||
else:
|
||
return render(request, 'mainapp/login_required.html')
|
||
|
||
|
||
class HomePageView(View):
|
||
def get(self, request):
|
||
if request.user.is_authenticated:
|
||
# Redirect to objitem list if authenticated
|
||
return redirect('objitem_list')
|
||
else:
|
||
return render(request, 'mainapp/login_required.html')
|
||
|
||
|
||
class LoadExcelDataView(LoginRequiredMixin, FormView):
|
||
template_name = 'mainapp/add_data_from_excel.html'
|
||
form_class = LoadExcelData
|
||
|
||
def form_valid(self, form):
|
||
uploaded_file = self.request.FILES['file']
|
||
selected_sat = form.cleaned_data['sat_choice']
|
||
number = form.cleaned_data['number_input']
|
||
|
||
try:
|
||
import io
|
||
df = pd.read_excel(io.BytesIO(uploaded_file.read()))
|
||
if number > 0:
|
||
df = df.head(number)
|
||
result = fill_data_from_df(df, selected_sat, self.request.user.customuser)
|
||
|
||
messages.success(self.request, f"Данные успешно загружены! Обработано строк: {result}")
|
||
return redirect('load_excel_data')
|
||
except Exception as e:
|
||
messages.error(self.request, f"Ошибка при обработке файла: {str(e)}")
|
||
return redirect('load_excel_data')
|
||
|
||
def form_invalid(self, form):
|
||
messages.error(self.request, "Форма заполнена некорректно.")
|
||
return super().form_invalid(form)
|
||
|
||
|
||
from django.views.generic import View
|
||
from django.core.paginator import Paginator
|
||
from django.db.models import Prefetch
|
||
from .models import Satellite, ObjItem, Parameter, Geo
|
||
|
||
class GetLocationsView(LoginRequiredMixin, View):
|
||
def get(self, request, sat_id):
|
||
locations = ObjItem.objects.filter(parameters_obj__id_satellite=sat_id)
|
||
if not locations:
|
||
return JsonResponse({'error': 'Объектов не найдено'}, status=400)
|
||
|
||
features = []
|
||
for loc in locations:
|
||
param = loc.parameters_obj.get()
|
||
features.append({
|
||
"type": "Feature",
|
||
"geometry": {
|
||
"type": "Point",
|
||
"coordinates": [loc.geo_obj.coords[0], loc.geo_obj.coords[1]]
|
||
},
|
||
"properties": {
|
||
"pol": param.polarization.name,
|
||
"freq": param.frequency*1000000,
|
||
"name": f"{loc.name}",
|
||
"id": loc.geo_obj.id
|
||
}
|
||
})
|
||
|
||
return JsonResponse({
|
||
"type": "FeatureCollection",
|
||
"features": features
|
||
})
|
||
|
||
class LoadCsvDataView(LoginRequiredMixin, FormView):
|
||
template_name = 'mainapp/add_data_from_csv.html'
|
||
form_class = LoadCsvData
|
||
|
||
def form_valid(self, form):
|
||
uploaded_file = self.request.FILES['file']
|
||
try:
|
||
# Read the file content and pass it directly to the function
|
||
content = uploaded_file.read()
|
||
if isinstance(content, bytes):
|
||
content = content.decode('utf-8')
|
||
|
||
get_points_from_csv(content, self.request.user.customuser)
|
||
messages.success(self.request, f"Данные успешно загружены!")
|
||
return redirect('load_csv_data')
|
||
except Exception as e:
|
||
messages.error(self.request, f"Ошибка при обработке файла: {str(e)}")
|
||
return redirect('load_csv_data')
|
||
|
||
def form_invalid(self, form):
|
||
messages.error(self.request, "Форма заполнена некорректно.")
|
||
return super().form_invalid(form)
|
||
|
||
|
||
from collections import defaultdict
|
||
|
||
@method_decorator(staff_member_required, name='dispatch')
|
||
class ShowMapView(UserPassesTestMixin, View):
|
||
def test_func(self):
|
||
return self.request.user.is_staff
|
||
|
||
def get(self, request):
|
||
ids = request.GET.get('ids', '')
|
||
points = []
|
||
if ids:
|
||
id_list = [int(x) for x in ids.split(',') if x.isdigit()]
|
||
locations = ObjItem.objects.filter(id__in=id_list).prefetch_related(
|
||
'parameters_obj__id_satellite',
|
||
'parameters_obj__polarization',
|
||
'parameters_obj__modulation',
|
||
'parameters_obj__standard',
|
||
'geo_obj'
|
||
)
|
||
for obj in locations:
|
||
param = obj.parameters_obj.get()
|
||
points.append({
|
||
'name': f"{obj.name}",
|
||
'freq': f"{param.frequency} [{param.freq_range}] МГц",
|
||
'point': (obj.geo_obj.coords.x, obj.geo_obj.coords.y)
|
||
})
|
||
else:
|
||
return redirect('admin')
|
||
grouped = defaultdict(list)
|
||
for p in points:
|
||
grouped[p["name"]].append({
|
||
'point': p["point"],
|
||
'frequency': p["freq"]
|
||
})
|
||
|
||
groups = [
|
||
{
|
||
"name": name,
|
||
"points": coords_list
|
||
}
|
||
for name, coords_list in grouped.items()
|
||
]
|
||
|
||
|
||
context = {
|
||
'groups': groups,
|
||
}
|
||
return render(request, 'admin/map_custom.html', context)
|
||
|
||
|
||
class ClusterTestView(LoginRequiredMixin, View):
|
||
def get(self, request):
|
||
objs = ObjItem.objects.filter(name__icontains="! Astra 4A 12654,040 [1,962] МГц H")
|
||
coords = []
|
||
for obj in objs:
|
||
if obj.geo_obj and obj.geo_obj.coords:
|
||
coords.append((obj.geo_obj.coords.coords[1], obj.geo_obj.coords.coords[0]))
|
||
get_clusters(coords)
|
||
|
||
return JsonResponse({"success": "ок"})
|
||
|
||
|
||
def custom_logout(request):
|
||
logout(request)
|
||
return redirect('home')
|
||
|
||
class UploadVchLoadView(LoginRequiredMixin, FormView):
|
||
template_name = 'mainapp/upload_html.html'
|
||
form_class = UploadVchLoad
|
||
|
||
def form_valid(self, form):
|
||
selected_sat = form.cleaned_data['sat_choice']
|
||
uploaded_file = self.request.FILES['file']
|
||
try:
|
||
get_vch_load_from_html(uploaded_file, selected_sat)
|
||
messages.success(self.request, "Файл успешно обработан")
|
||
except ValueError as e:
|
||
messages.error(self.request, f"Ошибка при чтении таблиц: {e}")
|
||
except Exception as e:
|
||
messages.error(self.request, f"Неизвестная ошибка: {e}")
|
||
return redirect('vch_load')
|
||
|
||
def form_invalid(self, form):
|
||
messages.error(self.request, "Форма заполнена некорректно.")
|
||
return super().form_invalid(form)
|
||
|
||
|
||
class LinkVchSigmaView(LoginRequiredMixin, FormView):
|
||
template_name = 'mainapp/link_vch.html'
|
||
form_class = VchLinkForm
|
||
|
||
def form_valid(self, form):
|
||
freq = form.cleaned_data['value1']
|
||
freq_range = form.cleaned_data['value2']
|
||
# ku_range = float(form.cleaned_data['ku_range'])
|
||
sat_id = form.cleaned_data['sat_choice']
|
||
# print(freq, freq_range, ku_range, sat_id.pk)
|
||
count_all, link_count = compare_and_link_vch_load(sat_id, freq, freq_range, 1)
|
||
messages.success(self.request, f"Привязано {link_count} из {count_all} объектов")
|
||
return redirect('link_vch_sigma')
|
||
|
||
def form_invalid(self, form):
|
||
return self.render_to_response(self.get_context_data(form=form))
|
||
|
||
|
||
class ProcessKubsatView(LoginRequiredMixin, FormView):
|
||
template_name = 'mainapp/process_kubsat.html'
|
||
form_class = NewEventForm
|
||
|
||
def form_valid(self, form):
|
||
# selected_sat = form.cleaned_data['sat_choice']
|
||
# selected_pol = form.cleaned_data['pol_choice']
|
||
uploaded_file = self.request.FILES['file']
|
||
try:
|
||
content = uploaded_file.read()
|
||
df = kub_report(BytesIO(content))
|
||
output = BytesIO()
|
||
with pd.ExcelWriter(output, engine='openpyxl') as writer:
|
||
df.to_excel(writer, index=False, sheet_name='Результат')
|
||
output.seek(0)
|
||
|
||
response = HttpResponse(
|
||
output.getvalue(),
|
||
content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
||
)
|
||
response['Content-Disposition'] = f'attachment; filename="kubsat_report.xlsx"'
|
||
|
||
messages.success(self.request, "Событие успешно обработано!")
|
||
return response
|
||
except Exception as e:
|
||
messages.error(self.request, f"Ошибка при обработке файла: {str(e)}")
|
||
return redirect('kubsat_excel')
|
||
# return redirect('kubsat_excel')
|
||
|
||
def form_invalid(self, form):
|
||
messages.error(self.request, "Форма заполнена некорректно.")
|
||
return super().form_invalid(form)
|
||
|
||
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')
|
||
|
||
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')
|
||
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')
|
||
range_max = request.GET.get('range_max')
|
||
snr_min = request.GET.get('snr_min')
|
||
snr_max = request.GET.get('snr_max')
|
||
bod_min = request.GET.get('bod_min')
|
||
bod_max = request.GET.get('bod_max')
|
||
search_query = request.GET.get('search')
|
||
selected_modulations = request.GET.getlist('modulation')
|
||
selected_polarizations = request.GET.getlist('polarization')
|
||
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
|
||
|
||
objects = ObjItem.objects.none()
|
||
|
||
if selected_satellites or selected_sat_id:
|
||
if selected_sat_id and not selected_satellites:
|
||
try:
|
||
selected_sat_id_single = int(selected_sat_id)
|
||
selected_satellites = [selected_sat_id_single]
|
||
except ValueError:
|
||
selected_satellites = []
|
||
|
||
if selected_satellites:
|
||
objects = ObjItem.objects.select_related(
|
||
'geo_obj',
|
||
'updated_by__user',
|
||
'created_by__user',
|
||
).prefetch_related(
|
||
'parameters_obj__id_satellite',
|
||
'parameters_obj__polarization',
|
||
'parameters_obj__modulation',
|
||
'parameters_obj__standard'
|
||
).filter(parameters_obj__id_satellite_id__in=selected_satellites)
|
||
else:
|
||
objects = ObjItem.objects.select_related(
|
||
'geo_obj',
|
||
'updated_by__user',
|
||
'created_by__user',
|
||
).prefetch_related(
|
||
'parameters_obj__id_satellite',
|
||
'parameters_obj__polarization',
|
||
'parameters_obj__modulation',
|
||
'parameters_obj__standard'
|
||
)
|
||
|
||
if freq_min is not None and freq_min.strip() != '':
|
||
try:
|
||
freq_min_val = float(freq_min)
|
||
objects = objects.filter(parameters_obj__frequency__gte=freq_min_val)
|
||
except ValueError:
|
||
pass
|
||
if freq_max is not None and freq_max.strip() != '':
|
||
try:
|
||
freq_max_val = float(freq_max)
|
||
objects = objects.filter(parameters_obj__frequency__lte=freq_max_val)
|
||
except ValueError:
|
||
pass
|
||
|
||
if range_min is not None and range_min.strip() != '':
|
||
try:
|
||
range_min_val = float(range_min)
|
||
objects = objects.filter(parameters_obj__freq_range__gte=range_min_val)
|
||
except ValueError:
|
||
pass
|
||
if range_max is not None and range_max.strip() != '':
|
||
try:
|
||
range_max_val = float(range_max)
|
||
objects = objects.filter(parameters_obj__freq_range__lte=range_max_val)
|
||
except ValueError:
|
||
pass
|
||
|
||
if snr_min is not None and snr_min.strip() != '':
|
||
try:
|
||
snr_min_val = float(snr_min)
|
||
objects = objects.filter(parameters_obj__snr__gte=snr_min_val)
|
||
except ValueError:
|
||
pass
|
||
if snr_max is not None and snr_max.strip() != '':
|
||
try:
|
||
snr_max_val = float(snr_max)
|
||
objects = objects.filter(parameters_obj__snr__lte=snr_max_val)
|
||
except ValueError:
|
||
pass
|
||
|
||
if bod_min is not None and bod_min.strip() != '':
|
||
try:
|
||
bod_min_val = float(bod_min)
|
||
objects = objects.filter(parameters_obj__bod_velocity__gte=bod_min_val)
|
||
except ValueError:
|
||
pass
|
||
if bod_max is not None and bod_max.strip() != '':
|
||
try:
|
||
bod_max_val = float(bod_max)
|
||
objects = objects.filter(parameters_obj__bod_velocity__lte=bod_max_val)
|
||
except ValueError:
|
||
pass
|
||
|
||
if selected_modulations:
|
||
objects = objects.filter(parameters_obj__modulation__id__in=selected_modulations)
|
||
|
||
if selected_polarizations:
|
||
objects = objects.filter(parameters_obj__polarization__id__in=selected_polarizations)
|
||
|
||
if has_kupsat == '1':
|
||
objects = objects.filter(geo_obj__coords_kupsat__isnull=False)
|
||
elif has_kupsat == '0':
|
||
objects = objects.filter(geo_obj__coords_kupsat__isnull=True)
|
||
|
||
if has_valid == '1':
|
||
objects = objects.filter(geo_obj__coords_valid__isnull=False)
|
||
elif has_valid == '0':
|
||
objects = objects.filter(geo_obj__coords_valid__isnull=True)
|
||
|
||
if search_query:
|
||
search_query = search_query.strip()
|
||
if search_query:
|
||
objects = objects.filter(
|
||
models.Q(name__icontains=search_query) |
|
||
models.Q(geo_obj__location__icontains=search_query)
|
||
)
|
||
else:
|
||
selected_sat_id = None
|
||
|
||
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)
|
||
|
||
processed_objects = []
|
||
for obj in page_obj:
|
||
param = None
|
||
if hasattr(obj, 'parameters_obj') and obj.parameters_obj.all():
|
||
param_list = list(obj.parameters_obj.all())
|
||
if param_list:
|
||
param = param_list[0]
|
||
|
||
geo_coords = "-"
|
||
kupsat_coords = "-"
|
||
valid_coords = "-"
|
||
distance_geo_kup = "-"
|
||
distance_geo_valid = "-"
|
||
distance_kup_valid = "-"
|
||
|
||
if obj.geo_obj:
|
||
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}"
|
||
|
||
if obj.geo_obj.coords_kupsat:
|
||
longitude = obj.geo_obj.coords_kupsat.coords[0]
|
||
latitude = obj.geo_obj.coords_kupsat.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"
|
||
kupsat_coords = f"{lat} {lon}"
|
||
elif obj.geo_obj.coords_kupsat is not None:
|
||
kupsat_coords = "-"
|
||
|
||
if obj.geo_obj.coords_valid:
|
||
longitude = obj.geo_obj.coords_valid.coords[0]
|
||
latitude = obj.geo_obj.coords_valid.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"
|
||
valid_coords = f"{lat} {lon}"
|
||
elif obj.geo_obj.coords_valid is not None:
|
||
valid_coords = "-"
|
||
|
||
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}"
|
||
|
||
satellite_name = "-"
|
||
frequency = "-"
|
||
freq_range = "-"
|
||
polarization_name = "-"
|
||
bod_velocity = "-"
|
||
modulation_name = "-"
|
||
snr = "-"
|
||
|
||
if param:
|
||
if hasattr(param, 'id_satellite') and param.id_satellite:
|
||
satellite_name = param.id_satellite.name if hasattr(param.id_satellite, 'name') else "-"
|
||
|
||
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 "-"
|
||
|
||
if hasattr(param, 'polarization') and param.polarization:
|
||
polarization_name = param.polarization.name if hasattr(param.polarization, 'name') else "-"
|
||
|
||
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 "-",
|
||
'satellite_name': satellite_name,
|
||
'frequency': frequency,
|
||
'freq_range': freq_range,
|
||
'polarization': polarization_name,
|
||
'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,
|
||
'distance_geo_kup': distance_geo_kup,
|
||
'distance_geo_valid': distance_geo_valid,
|
||
'distance_kup_valid': distance_kup_valid,
|
||
'updated_by': obj.updated_by if obj.updated_by else '-',
|
||
'obj': obj
|
||
})
|
||
|
||
modulations = Modulation.objects.all()
|
||
polarizations = Polarization.objects.all()
|
||
|
||
context = {
|
||
'satellites': satellites,
|
||
'selected_satellite_id': selected_sat_id,
|
||
'page_obj': page_obj,
|
||
'processed_objects': processed_objects,
|
||
'items_per_page': items_per_page,
|
||
'available_items_per_page': [50, 100, 500, 1000],
|
||
'freq_min': freq_min,
|
||
'freq_max': freq_max,
|
||
'range_min': range_min,
|
||
'range_max': range_max,
|
||
'snr_min': snr_min,
|
||
'snr_max': snr_max,
|
||
'bod_min': bod_min,
|
||
'bod_max': bod_max,
|
||
'search_query': search_query,
|
||
'selected_modulations': [int(x) for x in selected_modulations if x.isdigit()],
|
||
'selected_polarizations': [int(x) for x in selected_polarizations if x.isdigit()],
|
||
'selected_satellites': [int(x) for x in selected_satellites if x.isdigit()],
|
||
'has_kupsat': has_kupsat,
|
||
'has_valid': has_valid,
|
||
'modulations': modulations,
|
||
'polarizations': polarizations,
|
||
'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
|
||
form_class = ObjItemForm
|
||
template_name = 'mainapp/objitem_form.html'
|
||
success_url = reverse_lazy('home')
|
||
|
||
def test_func(self):
|
||
return self.request.user.customuser.role in ['admin', 'moderator']
|
||
|
||
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,
|
||
extra=0,
|
||
can_delete=True
|
||
)
|
||
|
||
if self.object:
|
||
parameter_queryset = self.object.parameters_obj.all()
|
||
context['parameter_forms'] = ParameterFormSet(
|
||
queryset=parameter_queryset,
|
||
prefix='parameters'
|
||
)
|
||
|
||
if hasattr(self.object, 'geo_obj'):
|
||
context['geo_form'] = GeoForm(instance=self.object.geo_obj, prefix='geo')
|
||
else:
|
||
context['geo_form'] = GeoForm(prefix='geo')
|
||
else:
|
||
context['parameter_forms'] = ParameterFormSet(
|
||
queryset=Parameter.objects.none(),
|
||
prefix='parameters'
|
||
)
|
||
context['geo_form'] = GeoForm(prefix='geo')
|
||
|
||
return context
|
||
|
||
def form_valid(self, form):
|
||
context = self.get_context_data()
|
||
parameter_forms = context['parameter_forms']
|
||
geo_form = context['geo_form']
|
||
|
||
# Сохраняем основной объект
|
||
self.object = form.save(commit=False)
|
||
self.object.updated_by = self.request.user.customuser
|
||
self.object.save()
|
||
|
||
# Сохраняем связанные параметры
|
||
if parameter_forms.is_valid():
|
||
instances = parameter_forms.save(commit=False)
|
||
for instance in instances:
|
||
instance.save()
|
||
instance.objitems.set([self.object])
|
||
|
||
# Сохраняем геоданные
|
||
geo_instance = None
|
||
if hasattr(self.object, 'geo_obj'):
|
||
geo_instance = self.object.geo_obj
|
||
|
||
# Создаем или обновляем гео-объект
|
||
if geo_instance is None:
|
||
geo_instance = Geo(objitem=self.object)
|
||
|
||
# Обновляем поля из geo_form
|
||
if geo_form.is_valid():
|
||
geo_instance.location = geo_form.cleaned_data['location']
|
||
geo_instance.comment = geo_form.cleaned_data['comment']
|
||
geo_instance.is_average = geo_form.cleaned_data['is_average']
|
||
|
||
# Обрабатываем координаты геолокации
|
||
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), 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), 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), srid=4326)
|
||
|
||
# Обрабатываем дату/время
|
||
timestamp_date = self.request.POST.get('timestamp_date')
|
||
timestamp_time = self.request.POST.get('timestamp_time')
|
||
if timestamp_date and timestamp_time:
|
||
naive_datetime = datetime.strptime(f"{timestamp_date} {timestamp_time}", "%Y-%m-%d %H:%M")
|
||
geo_instance.timestamp = naive_datetime
|
||
|
||
geo_instance.save()
|
||
|
||
messages.success(self.request, 'Объект успешно сохранён!')
|
||
return super().form_valid(form)
|
||
|
||
class ObjItemCreateView(LoginRequiredMixin, UserPassesTestMixin, CreateView):
|
||
model = ObjItem
|
||
form_class = ObjItemForm
|
||
template_name = 'mainapp/objitem_form.html'
|
||
success_url = reverse_lazy('home')
|
||
|
||
def test_func(self):
|
||
return self.request.user.customuser.role in ['admin', 'moderator']
|
||
|
||
def get_context_data(self, **kwargs):
|
||
context = super().get_context_data(**kwargs)
|
||
|
||
ParameterFormSet = modelformset_factory(
|
||
Parameter,
|
||
form=ParameterForm,
|
||
extra=1,
|
||
can_delete=True
|
||
)
|
||
|
||
context['parameter_forms'] = ParameterFormSet(
|
||
queryset=Parameter.objects.none(),
|
||
prefix='parameters'
|
||
)
|
||
|
||
context['geo_form'] = GeoForm(prefix='geo')
|
||
|
||
return context
|
||
|
||
def form_valid(self, form):
|
||
context = self.get_context_data()
|
||
parameter_forms = context['parameter_forms']
|
||
geo_form = context['geo_form']
|
||
|
||
# Сохраняем основной объект
|
||
self.object = form.save(commit=False)
|
||
self.object.created_by = self.request.user.customuser
|
||
self.object.updated_by = self.request.user.customuser
|
||
self.object.save()
|
||
|
||
# Сохраняем связанные параметры
|
||
if parameter_forms.is_valid():
|
||
instances = parameter_forms.save(commit=False)
|
||
for instance in instances:
|
||
instance.save()
|
||
instance.objitems.add(self.object)
|
||
|
||
# Создаем гео-объект
|
||
geo_instance = Geo(objitem=self.object)
|
||
|
||
# Обновляем поля из geo_form
|
||
if geo_form.is_valid():
|
||
geo_instance.location = geo_form.cleaned_data['location']
|
||
geo_instance.comment = geo_form.cleaned_data['comment']
|
||
geo_instance.is_average = geo_form.cleaned_data['is_average']
|
||
|
||
# Обрабатываем координаты геолокации
|
||
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), 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), 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), srid=4326)
|
||
|
||
# Обрабатываем дату/время
|
||
timestamp_date = self.request.POST.get('timestamp_date')
|
||
timestamp_time = self.request.POST.get('timestamp_time')
|
||
if timestamp_date and timestamp_time:
|
||
naive_datetime = datetime.strptime(f"{timestamp_date} {timestamp_time}", "%Y-%m-%d %H:%M")
|
||
geo_instance.timestamp = naive_datetime
|
||
|
||
geo_instance.save()
|
||
|
||
messages.success(self.request, 'Объект успешно создан!')
|
||
return super().form_valid(form)
|
||
|
||
class ObjItemDeleteView(LoginRequiredMixin, UserPassesTestMixin, DeleteView):
|
||
model = ObjItem
|
||
template_name = 'mainapp/objitem_confirm_delete.html'
|
||
success_url = reverse_lazy('home')
|
||
|
||
def test_func(self):
|
||
return self.request.user.customuser.role in ['admin', 'moderator']
|
||
|
||
def delete(self, request, *args, **kwargs):
|
||
messages.success(self.request, 'Объект успешно удалён!')
|
||
return super().delete(request, *args, **kwargs) |