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

This commit is contained in:
2025-11-01 13:57:50 +03:00
parent e01785fa53
commit c8a951eac6
10 changed files with 1058 additions and 50 deletions

View File

@@ -6,10 +6,13 @@ 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.views.generic import TemplateView, FormView
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,
@@ -20,10 +23,21 @@ from .utils import (
kub_report
)
from mapsapp.utils import parse_transponders_from_json, parse_transponders_from_xml
from .forms import LoadExcelData, LoadCsvData, UploadFileForm, VchLinkForm, UploadVchLoad, NewEventForm
from .forms import (
LoadExcelData,
LoadCsvData,
UploadFileForm,
VchLinkForm,
UploadVchLoad,
NewEventForm,
ObjItemForm,
ParameterForm,
GeoForm
)
from .models import ObjItem
from .clusters import get_clusters
from io import BytesIO
from datetime import datetime
@@ -93,7 +107,7 @@ class LoadExcelDataView(LoginRequiredMixin, FormView):
df = pd.read_excel(io.BytesIO(uploaded_file.read()))
if number > 0:
df = df.head(number)
result = fill_data_from_df(df, selected_sat)
result = fill_data_from_df(df, selected_sat, self.request.user.customuser)
messages.success(self.request, f"Данные успешно загружены! Обработано строк: {result}")
return redirect('load_excel_data')
@@ -151,7 +165,7 @@ class LoadCsvDataView(LoginRequiredMixin, FormView):
if isinstance(content, bytes):
content = content.decode('utf-8')
get_points_from_csv(content)
get_points_from_csv(content, self.request.user.customuser)
messages.success(self.request, f"Данные успешно загружены!")
return redirect('load_csv_data')
except Exception as e:
@@ -331,7 +345,7 @@ class ObjItemListView(LoginRequiredMixin, View):
try:
items_per_page = int(items_per_page)
except ValueError:
items_per_page = 25
items_per_page = 50
# Only filter objects by selected satellite if provided (no data shown by default)
objects = ObjItem.objects.none() # Initially empty
@@ -348,11 +362,11 @@ class ObjItemListView(LoginRequiredMixin, View):
# Start with the basic filter if any satellites are selected
if selected_satellites:
# Start with the basic filter
# Start with the basic filter - optimized with prefetch_related for all related objects
objects = ObjItem.objects.select_related(
'id_user_add__user',
'geo_obj',
'updated_by__user'
'updated_by__user',
'created_by__user',
).prefetch_related(
'parameters_obj__id_satellite',
'parameters_obj__polarization',
@@ -362,9 +376,9 @@ class ObjItemListView(LoginRequiredMixin, View):
else:
# If no satellites are selected, start with all objects
objects = ObjItem.objects.select_related(
'id_user_add__user',
'geo_obj',
'updated_by__user'
'updated_by__user',
'created_by__user',
).prefetch_related(
'parameters_obj__id_satellite',
'parameters_obj__polarization',
@@ -468,8 +482,13 @@ class ObjItemListView(LoginRequiredMixin, View):
# Prepare the data to include calculated fields for the template
processed_objects = []
for obj in page_obj:
# Get the first parameter
param = obj.parameters_obj.first() if obj.parameters_obj.exists() else None
# 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
geo_coords = "-"
@@ -518,22 +537,51 @@ class ObjItemListView(LoginRequiredMixin, View):
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 = "-"
polarization_name = "-"
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 "-",
'satellite_name': param.id_satellite.name if param and param.id_satellite else "-",
'frequency': f"{param.frequency:.3f}" if param and param.frequency else "-",
'freq_range': f"{param.freq_range:.3f}" if param and param.freq_range else "-",
'polarization': param.polarization.name if param and param.polarization else "-",
'bod_velocity': f"{param.bod_velocity:.0f}" if param and param.bod_velocity else "-",
'modulation': param.modulation.name if param and param.modulation else "-",
'snr': f"{param.snr:.0f}" if param and param.snr else "-",
'satellite_name': satellite_name,
'frequency': frequency,
'freq_range': freq_range,
'polarization': polarization_name,
'bod_velocity': bod_velocity,
'modulation': modulation_name,
'snr': snr,
'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
})
@@ -571,4 +619,209 @@ class ObjItemListView(LoginRequiredMixin, View):
'full_width_page': True,
}
return render(request, 'mainapp/objitem_list.html', context)
return render(request, 'mainapp/objitem_list.html', context)
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))
# Обрабатываем координаты Кубсата
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))
# Обрабатываем координаты оперативников
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))
# Обрабатываем дату/время
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))
# Обрабатываем координаты Кубсата
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))
# Обрабатываем координаты оперативников
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))
# Обрабатываем дату/время
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)