Files
dbstorage/dbapp/mainapp/views/transponder.py

376 lines
15 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
Transponder CRUD operations and related views.
"""
from datetime import datetime
from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.paginator import Paginator
from django.db.models import Count, Q
from django.http import JsonResponse
from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse, reverse_lazy
from django.views import View
from django.views.generic import CreateView, UpdateView
from mapsapp.models import Transponders
from ..forms import TransponderForm
from ..mixins import RoleRequiredMixin, FormMessageMixin
from ..models import Satellite, Polarization
from ..utils import parse_pagination_params
class TransponderListView(LoginRequiredMixin, View):
"""View for displaying a list of transponders with filtering and pagination."""
def get(self, request):
# Get pagination parameters
page_number, items_per_page = parse_pagination_params(request)
# Get sorting parameters (default to satellite and downlink)
sort_param = request.GET.get("sort", "sat_id__name")
# Get filter parameters
search_query = request.GET.get("search", "").strip()
selected_satellites = request.GET.getlist("satellite_id")
selected_polarizations = request.GET.getlist("polarization")
downlink_min = request.GET.get("downlink_min", "").strip()
downlink_max = request.GET.get("downlink_max", "").strip()
uplink_min = request.GET.get("uplink_min", "").strip()
uplink_max = request.GET.get("uplink_max", "").strip()
freq_range_min = request.GET.get("freq_range_min", "").strip()
freq_range_max = request.GET.get("freq_range_max", "").strip()
snr_min = request.GET.get("snr_min", "").strip()
snr_max = request.GET.get("snr_max", "").strip()
date_from = request.GET.get("date_from", "").strip()
date_to = request.GET.get("date_to", "").strip()
# Get all satellites and polarizations for filters
satellites = Satellite.objects.filter(
tran_satellite__isnull=False
).distinct().only("id", "name").order_by("name")
polarizations = Polarization.objects.all().order_by("name")
# Get all transponders with query optimization
transponders = Transponders.objects.select_related(
'sat_id',
'polarization',
'created_by__user',
'updated_by__user'
).annotate(
objitem_count=Count('transponder_objitems')
)
# Apply filters
# Filter by satellites
if selected_satellites:
transponders = transponders.filter(sat_id_id__in=selected_satellites)
# Filter by polarizations
if selected_polarizations:
transponders = transponders.filter(polarization_id__in=selected_polarizations)
# Filter by downlink frequency
if downlink_min:
try:
min_val = float(downlink_min)
transponders = transponders.filter(downlink__gte=min_val)
except ValueError:
pass
if downlink_max:
try:
max_val = float(downlink_max)
transponders = transponders.filter(downlink__lte=max_val)
except ValueError:
pass
# Filter by uplink frequency
if uplink_min:
try:
min_val = float(uplink_min)
transponders = transponders.filter(uplink__gte=min_val)
except ValueError:
pass
if uplink_max:
try:
max_val = float(uplink_max)
transponders = transponders.filter(uplink__lte=max_val)
except ValueError:
pass
# Filter by frequency range
if freq_range_min:
try:
min_val = float(freq_range_min)
transponders = transponders.filter(frequency_range__gte=min_val)
except ValueError:
pass
if freq_range_max:
try:
max_val = float(freq_range_max)
transponders = transponders.filter(frequency_range__lte=max_val)
except ValueError:
pass
# Filter by SNR
if snr_min:
try:
min_val = float(snr_min)
transponders = transponders.filter(snr__gte=min_val)
except ValueError:
pass
if snr_max:
try:
max_val = float(snr_max)
transponders = transponders.filter(snr__lte=max_val)
except ValueError:
pass
# Filter by creation date range
if date_from:
try:
date_from_obj = datetime.strptime(date_from, "%Y-%m-%d")
transponders = transponders.filter(created_at__gte=date_from_obj)
except (ValueError, TypeError):
pass
if date_to:
try:
from datetime import timedelta
date_to_obj = datetime.strptime(date_to, "%Y-%m-%d")
# Add one day to include entire end date
date_to_obj = date_to_obj + timedelta(days=1)
transponders = transponders.filter(created_at__lt=date_to_obj)
except (ValueError, TypeError):
pass
# Search by name or zone name
if search_query:
transponders = transponders.filter(
Q(name__icontains=search_query) |
Q(zone_name__icontains=search_query) |
Q(sat_id__name__icontains=search_query)
)
# Apply sorting
valid_sort_fields = {
"sat_id__name": "sat_id__name",
"-sat_id__name": "-sat_id__name",
"name": "name",
"-name": "-name",
"downlink": "downlink",
"-downlink": "-downlink",
"uplink": "uplink",
"-uplink": "-uplink",
"frequency_range": "frequency_range",
"-frequency_range": "-frequency_range",
"zone_name": "zone_name",
"-zone_name": "-zone_name",
"polarization__name": "polarization__name",
"-polarization__name": "-polarization__name",
"snr": "snr",
"-snr": "-snr",
"created_at": "created_at",
"-created_at": "-created_at",
"updated_at": "updated_at",
"-updated_at": "-updated_at",
"objitem_count": "objitem_count",
"-objitem_count": "-objitem_count",
}
if sort_param in valid_sort_fields:
transponders = transponders.order_by(valid_sort_fields[sort_param])
# Create paginator
paginator = Paginator(transponders, items_per_page)
page_obj = paginator.get_page(page_number)
# Prepare data for display
processed_transponders = []
for transponder in page_obj:
processed_transponders.append({
'id': transponder.id,
'name': transponder.name or "-",
'satellite': transponder.sat_id.name if transponder.sat_id else "-",
'satellite_id': transponder.sat_id.id if transponder.sat_id else None,
'downlink': f"{transponder.downlink:.3f}" if transponder.downlink else "-",
'uplink': f"{transponder.uplink:.3f}" if transponder.uplink else "-",
'frequency_range': f"{transponder.frequency_range:.3f}" if transponder.frequency_range else "-",
'transfer': f"{transponder.transfer:.3f}" if transponder.transfer else "-",
'zone_name': transponder.zone_name or "-",
'polarization': transponder.polarization.name if transponder.polarization else "-",
'snr': f"{transponder.snr:.1f}" if transponder.snr else "-",
'objitem_count': transponder.objitem_count,
'created_at': transponder.created_at,
'updated_at': transponder.updated_at,
'created_by': transponder.created_by if transponder.created_by else "-",
'updated_by': transponder.updated_by if transponder.updated_by else "-",
})
# Prepare context for template
context = {
'page_obj': page_obj,
'processed_transponders': processed_transponders,
'items_per_page': items_per_page,
'available_items_per_page': [50, 100, 500, 1000],
'sort': sort_param,
'search_query': search_query,
'satellites': satellites,
'polarizations': polarizations,
'selected_satellites': [
int(x) if isinstance(x, str) else x for x in selected_satellites
if (isinstance(x, int) or (isinstance(x, str) and x.isdigit()))
],
'selected_polarizations': [
int(x) if isinstance(x, str) else x for x in selected_polarizations
if (isinstance(x, int) or (isinstance(x, str) and x.isdigit()))
],
'downlink_min': downlink_min,
'downlink_max': downlink_max,
'uplink_min': uplink_min,
'uplink_max': uplink_max,
'freq_range_min': freq_range_min,
'freq_range_max': freq_range_max,
'snr_min': snr_min,
'snr_max': snr_max,
'date_from': date_from,
'date_to': date_to,
'full_width_page': True,
}
return render(request, "mainapp/transponder_list.html", context)
class TransponderCreateView(RoleRequiredMixin, FormMessageMixin, CreateView):
"""View for creating a new transponder."""
model = Transponders
form_class = TransponderForm
template_name = "mainapp/transponder_form.html"
success_url = reverse_lazy("mainapp:transponder_list")
success_message = "Транспондер успешно создан!"
required_roles = ["admin", "moderator"]
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['action'] = 'create'
context['title'] = 'Создание транспондера'
return context
def form_valid(self, form):
form.instance.created_by = self.request.user.customuser
form.instance.updated_by = self.request.user.customuser
return super().form_valid(form)
class TransponderUpdateView(RoleRequiredMixin, FormMessageMixin, UpdateView):
"""View for updating an existing transponder."""
model = Transponders
form_class = TransponderForm
template_name = "mainapp/transponder_form.html"
success_url = reverse_lazy("mainapp:transponder_list")
success_message = "Транспондер успешно обновлен!"
required_roles = ["admin", "moderator"]
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['action'] = 'update'
context['title'] = f'Редактирование транспондера #{self.object.id}'
# Get related objitems count
context['objitem_count'] = self.object.transponder_objitems.count()
return context
def form_valid(self, form):
form.instance.updated_by = self.request.user.customuser
return super().form_valid(form)
class DeleteSelectedTranspondersView(RoleRequiredMixin, View):
"""View for deleting multiple selected transponders with confirmation."""
required_roles = ["admin", "moderator"]
def get(self, request):
"""Show confirmation page with details about transponders to be deleted."""
ids = request.GET.get("ids", "")
if not ids:
messages.error(request, "Не выбраны транспондеры для удаления")
return redirect('mainapp:transponder_list')
try:
id_list = [int(x) for x in ids.split(",") if x.isdigit()]
transponders = Transponders.objects.filter(id__in=id_list).select_related(
'sat_id',
'polarization'
).annotate(
objitem_count=Count('transponder_objitems')
)
# Prepare detailed information about transponders
transponders_info = []
total_objitems = 0
for transponder in transponders:
objitem_count = transponder.objitem_count
total_objitems += objitem_count
transponders_info.append({
'id': transponder.id,
'name': transponder.name or "-",
'satellite': transponder.sat_id.name if transponder.sat_id else "-",
'downlink': f"{transponder.downlink:.3f}" if transponder.downlink else "-",
'frequency_range': f"{transponder.frequency_range:.3f}" if transponder.frequency_range else "-",
'objitem_count': objitem_count,
})
context = {
'transponders_info': transponders_info,
'total_transponders': len(transponders_info),
'total_objitems': total_objitems,
'ids': ids,
}
return render(request, 'mainapp/transponder_bulk_delete_confirm.html', context)
except Exception as e:
messages.error(request, f'Ошибка при подготовке удаления: {str(e)}')
return redirect('mainapp:transponder_list')
def post(self, request):
"""Actually delete the selected transponders."""
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()]
# Get count before deletion
transponders = Transponders.objects.filter(id__in=id_list)
deleted_count = transponders.count()
# Delete transponders (cascade will handle related objitems)
transponders.delete()
messages.success(
request,
f'Успешно удалено транспондеров: {deleted_count}'
)
return JsonResponse({
"success": True,
"message": f"Успешно удалено транспондеров: {deleted_count}",
"deleted_count": deleted_count,
})
except Exception as e:
return JsonResponse({"error": f"Ошибка при удалении: {str(e)}"}, status=500)