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

430 lines
18 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.

from django.contrib import messages
from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.paginator import Paginator
from django.db import transaction
from django.db.models import Q
from django.http import JsonResponse
from django.shortcuts import render
from django.views import View
from django.views.decorators.http import require_http_methods
import json
from ..models import (
TechAnalyze,
Satellite,
Polarization,
Modulation,
Standard,
ObjItem,
Parameter,
)
from ..mixins import RoleRequiredMixin
from ..utils import parse_pagination_params
class TechAnalyzeEntryView(LoginRequiredMixin, View):
"""
Представление для ввода данных технического анализа.
"""
def get(self, request):
satellites = Satellite.objects.all().order_by('name')
context = {
'satellites': satellites,
}
return render(request, 'mainapp/tech_analyze_entry.html', context)
class TechAnalyzeSaveView(LoginRequiredMixin, View):
"""
API endpoint для сохранения данных технического анализа.
"""
def post(self, request):
try:
data = json.loads(request.body)
satellite_id = data.get('satellite_id')
rows = data.get('rows', [])
if not satellite_id:
return JsonResponse({
'success': False,
'error': 'Не выбран спутник'
}, status=400)
if not rows:
return JsonResponse({
'success': False,
'error': 'Нет данных для сохранения'
}, status=400)
try:
satellite = Satellite.objects.get(id=satellite_id)
except Satellite.DoesNotExist:
return JsonResponse({
'success': False,
'error': 'Спутник не найден'
}, status=404)
created_count = 0
updated_count = 0
errors = []
with transaction.atomic():
for idx, row in enumerate(rows, start=1):
try:
name = row.get('name', '').strip()
if not name:
errors.append(f"Строка {idx}: отсутствует имя")
continue
# Обработка поляризации
polarization_name = row.get('polarization', '').strip() or '-'
polarization, _ = Polarization.objects.get_or_create(name=polarization_name)
# Обработка модуляции
modulation_name = row.get('modulation', '').strip() or '-'
modulation, _ = Modulation.objects.get_or_create(name=modulation_name)
# Обработка стандарта
standard_name = row.get('standard', '').strip()
if standard_name.lower() == 'unknown':
standard_name = '-'
if not standard_name:
standard_name = '-'
standard, _ = Standard.objects.get_or_create(name=standard_name)
# Обработка числовых полей
frequency = row.get('frequency')
if frequency:
try:
frequency = float(str(frequency).replace(',', '.'))
except (ValueError, TypeError):
frequency = 0
else:
frequency = 0
freq_range = row.get('freq_range')
if freq_range:
try:
freq_range = float(str(freq_range).replace(',', '.'))
except (ValueError, TypeError):
freq_range = 0
else:
freq_range = 0
bod_velocity = row.get('bod_velocity')
if bod_velocity:
try:
bod_velocity = float(str(bod_velocity).replace(',', '.'))
except (ValueError, TypeError):
bod_velocity = 0
else:
bod_velocity = 0
note = row.get('note', '').strip()
# Создание или обновление записи
tech_analyze, created = TechAnalyze.objects.update_or_create(
name=name,
defaults={
'satellite': satellite,
'polarization': polarization,
'frequency': frequency,
'freq_range': freq_range,
'bod_velocity': bod_velocity,
'modulation': modulation,
'standard': standard,
'note': note,
'updated_by': request.user.customuser if hasattr(request.user, 'customuser') else None,
}
)
if created:
tech_analyze.created_by = request.user.customuser if hasattr(request.user, 'customuser') else None
tech_analyze.save()
created_count += 1
else:
updated_count += 1
except Exception as e:
errors.append(f"Строка {idx}: {str(e)}")
response_data = {
'success': True,
'created': created_count,
'updated': updated_count,
'total': created_count + updated_count,
}
if errors:
response_data['errors'] = errors
return JsonResponse(response_data)
except json.JSONDecodeError:
return JsonResponse({
'success': False,
'error': 'Неверный формат данных'
}, status=400)
except Exception as e:
return JsonResponse({
'success': False,
'error': str(e)
}, status=500)
class LinkExistingPointsView(LoginRequiredMixin, View):
"""
API endpoint для привязки существующих точек к данным теханализа.
Алгоритм:
1. Получить все ObjItem для выбранного спутника
2. Для каждого ObjItem:
- Извлечь имя источника
- Найти соответствующую запись TechAnalyze по имени и спутнику
- Если найдена и данные отсутствуют в Parameter:
* Обновить модуляцию (если "-")
* Обновить символьную скорость (если -1.0 или None)
* Обновить стандарт (если "-")
"""
def post(self, request):
try:
data = json.loads(request.body)
satellite_id = data.get('satellite_id')
if not satellite_id:
return JsonResponse({
'success': False,
'error': 'Не выбран спутник'
}, status=400)
try:
satellite = Satellite.objects.get(id=satellite_id)
except Satellite.DoesNotExist:
return JsonResponse({
'success': False,
'error': 'Спутник не найден'
}, status=404)
# Получаем все ObjItem для данного спутника
objitems = ObjItem.objects.filter(
parameter_obj__id_satellite=satellite
).select_related('parameter_obj', 'parameter_obj__modulation', 'parameter_obj__standard')
updated_count = 0
skipped_count = 0
errors = []
with transaction.atomic():
for objitem in objitems:
try:
if not objitem.parameter_obj:
skipped_count += 1
continue
parameter = objitem.parameter_obj
source_name = objitem.name
# Проверяем, нужно ли обновлять данные
needs_update = (
(parameter.modulation and parameter.modulation.name == "-") or
parameter.bod_velocity is None or
parameter.bod_velocity == -1.0 or
parameter.bod_velocity == 0 or
(parameter.standard and parameter.standard.name == "-")
)
if not needs_update:
skipped_count += 1
continue
# Ищем данные в TechAnalyze по имени и спутнику
tech_analyze = TechAnalyze.objects.filter(
name=source_name,
satellite=satellite
).select_related('modulation', 'standard').first()
if not tech_analyze:
skipped_count += 1
continue
# Обновляем данные
updated = False
# Обновляем модуляцию
if parameter.modulation and parameter.modulation.name == "-" and tech_analyze.modulation:
parameter.modulation = tech_analyze.modulation
updated = True
# Обновляем символьную скорость
if (parameter.bod_velocity is None or parameter.bod_velocity == -1.0 or parameter.bod_velocity == 0) and \
tech_analyze.bod_velocity and tech_analyze.bod_velocity > 0:
parameter.bod_velocity = tech_analyze.bod_velocity
updated = True
# Обновляем стандарт
if parameter.standard and parameter.standard.name == "-" and tech_analyze.standard:
parameter.standard = tech_analyze.standard
updated = True
if updated:
parameter.save()
updated_count += 1
else:
skipped_count += 1
except Exception as e:
errors.append(f"ObjItem {objitem.id}: {str(e)}")
response_data = {
'success': True,
'updated': updated_count,
'skipped': skipped_count,
'total': objitems.count(),
}
if errors:
response_data['errors'] = errors
return JsonResponse(response_data)
except json.JSONDecodeError:
return JsonResponse({
'success': False,
'error': 'Неверный формат данных'
}, status=400)
except Exception as e:
return JsonResponse({
'success': False,
'error': str(e)
}, status=500)
class TechAnalyzeListView(LoginRequiredMixin, View):
"""
Представление для отображения списка данных технического анализа.
"""
def get(self, request):
# Получаем список спутников для фильтра
satellites = Satellite.objects.all().order_by('name')
# Получаем параметры из URL для передачи в шаблон
search_query = request.GET.get('search', '').strip()
satellite_ids = request.GET.getlist('satellite_id')
items_per_page = int(request.GET.get('items_per_page', 50))
context = {
'satellites': satellites,
'selected_satellites': [int(sid) for sid in satellite_ids if sid],
'search_query': search_query,
'items_per_page': items_per_page,
'available_items_per_page': [25, 50, 100, 200, 500],
'full_width_page': True,
}
return render(request, 'mainapp/tech_analyze_list.html', context)
class TechAnalyzeDeleteView(LoginRequiredMixin, RoleRequiredMixin, View):
"""
API endpoint для удаления выбранных записей теханализа.
"""
allowed_roles = ['admin', 'moderator']
def post(self, request):
try:
data = json.loads(request.body)
ids = data.get('ids', [])
if not ids:
return JsonResponse({
'success': False,
'error': 'Не выбраны записи для удаления'
}, status=400)
# Удаляем записи
deleted_count, _ = TechAnalyze.objects.filter(id__in=ids).delete()
return JsonResponse({
'success': True,
'deleted': deleted_count,
'message': f'Удалено записей: {deleted_count}'
})
except json.JSONDecodeError:
return JsonResponse({
'success': False,
'error': 'Неверный формат данных'
}, status=400)
except Exception as e:
return JsonResponse({
'success': False,
'error': str(e)
}, status=500)
class TechAnalyzeAPIView(LoginRequiredMixin, View):
"""
API endpoint для получения данных теханализа в формате для Tabulator.
"""
def get(self, request):
# Получаем параметры фильтрации
search_query = request.GET.get('search', '').strip()
satellite_ids = request.GET.getlist('satellite_id')
# Получаем параметры пагинации от Tabulator
page = int(request.GET.get('page', 1))
size = int(request.GET.get('size', 50))
# Базовый queryset
tech_analyzes = TechAnalyze.objects.select_related(
'satellite', 'polarization', 'modulation', 'standard', 'created_by', 'updated_by'
).order_by('-created_at')
# Применяем фильтры
if search_query:
tech_analyzes = tech_analyzes.filter(
Q(name__icontains=search_query) |
Q(id__icontains=search_query)
)
if satellite_ids:
tech_analyzes = tech_analyzes.filter(satellite_id__in=satellite_ids)
# Пагинация
paginator = Paginator(tech_analyzes, size)
page_obj = paginator.get_page(page)
# Формируем данные для Tabulator
results = []
for item in page_obj:
results.append({
'id': item.id,
'name': item.name or '',
'satellite_id': item.satellite.id if item.satellite else None,
'satellite_name': item.satellite.name if item.satellite else '-',
'frequency': float(item.frequency) if item.frequency else 0,
'freq_range': float(item.freq_range) if item.freq_range else 0,
'bod_velocity': float(item.bod_velocity) if item.bod_velocity else 0,
'polarization_name': item.polarization.name if item.polarization else '-',
'modulation_name': item.modulation.name if item.modulation else '-',
'standard_name': item.standard.name if item.standard else '-',
'note': item.note or '',
'created_at': item.created_at.isoformat() if item.created_at else None,
'updated_at': item.updated_at.isoformat() if item.updated_at else None,
})
return JsonResponse({
'last_page': paginator.num_pages,
'data': results,
})