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 ShowSelectedObjectsMapView(LoginRequiredMixin, View): 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('objitem_list') # Group points by object name from collections import defaultdict 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, 'mainapp/objitem_map.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) class DeleteSelectedObjectsView(LoginRequiredMixin, View): def post(self, request): if request.user.customuser.role not in ['admin', 'moderator']: return JsonResponse({'error': 'У вас нет прав для удаления объектов'}, status=403) ids = request.POST.get('ids', '') if not ids: return JsonResponse({'error': 'Нет ID для удаления'}, status=400) try: id_list = [int(x) for x in ids.split(',') if x.isdigit()] deleted_count, _ = ObjItem.objects.filter(id__in=id_list).delete() return JsonResponse({ 'success': True, 'message': 'Объект успешно удалён', # 'deleted_count': deleted_count }) except Exception as e: return JsonResponse({'error': f'Ошибка при удалении: {str(e)}'}, status=500) 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 = "-" geo_timestamp = "-" geo_location = "-" kupsat_coords = "-" valid_coords = "-" distance_geo_kup = "-" distance_geo_valid = "-" distance_kup_valid = "-" if obj.geo_obj: geo_timestamp = obj.geo_obj.timestamp geo_location = obj.geo_obj.location 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_location': geo_location, '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)