221 lines
9.1 KiB
Python
221 lines
9.1 KiB
Python
"""
|
||
LyngSat related views for data synchronization and linking.
|
||
"""
|
||
from django.contrib import messages
|
||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||
from django.shortcuts import redirect, render
|
||
from django.urls import reverse_lazy
|
||
from django.views import View
|
||
from django.views.generic import FormView
|
||
|
||
from ..forms import FillLyngsatDataForm, LinkLyngsatForm
|
||
from ..mixins import FormMessageMixin
|
||
from ..models import ObjItem
|
||
|
||
|
||
class LinkLyngsatSourcesView(LoginRequiredMixin, FormMessageMixin, FormView):
|
||
"""View for linking LyngSat sources to objects."""
|
||
|
||
template_name = "mainapp/link_lyngsat.html"
|
||
form_class = LinkLyngsatForm
|
||
success_message = "Привязка источников LyngSat завершена"
|
||
error_message = "Ошибка при привязке источников"
|
||
|
||
def form_valid(self, form):
|
||
from lyngsatapp.models import LyngSat
|
||
|
||
satellites = form.cleaned_data.get("satellites")
|
||
frequency_tolerance = form.cleaned_data.get("frequency_tolerance", 0.5)
|
||
|
||
# If satellites not selected, process all
|
||
if satellites:
|
||
objitems = ObjItem.objects.filter(
|
||
parameter_obj__id_satellite__in=satellites
|
||
).select_related('parameter_obj', 'parameter_obj__polarization')
|
||
else:
|
||
objitems = ObjItem.objects.filter(
|
||
parameter_obj__isnull=False
|
||
).select_related('parameter_obj', 'parameter_obj__polarization')
|
||
|
||
linked_count = 0
|
||
total_count = objitems.count()
|
||
|
||
for objitem in objitems:
|
||
if not hasattr(objitem, 'parameter_obj') or not objitem.parameter_obj:
|
||
continue
|
||
|
||
param = objitem.parameter_obj
|
||
|
||
# Round object frequency to 1 decimal place
|
||
if param.frequency:
|
||
rounded_freq = round(param.frequency, 1) # Round to 1 decimal place
|
||
|
||
# Find matching LyngSat source
|
||
# Compare by rounded frequency (with tolerance) and polarization
|
||
# LyngSat frequencies are also rounded to 1 decimal place for comparison
|
||
lyngsat_sources = LyngSat.objects.filter(
|
||
id_satellite=param.id_satellite,
|
||
polarization=param.polarization
|
||
).select_related('id_satellite', 'polarization')
|
||
|
||
# Filter by rounded frequency with tolerance
|
||
matching_sources = []
|
||
for lyngsat in lyngsat_sources:
|
||
if lyngsat.frequency:
|
||
rounded_lyngsat_freq = round(lyngsat.frequency, 1)
|
||
if abs(rounded_lyngsat_freq - rounded_freq) <= frequency_tolerance:
|
||
matching_sources.append(lyngsat)
|
||
|
||
if matching_sources:
|
||
# Take first matching source (sorted by frequency difference)
|
||
matching_sources.sort(key=lambda x: abs(round(x.frequency, 1) - rounded_freq))
|
||
objitem.lyngsat_source = matching_sources[0]
|
||
objitem.save(update_fields=['lyngsat_source'])
|
||
|
||
# Update Source with ObjectInfo and ObjectOwnership for TV
|
||
if objitem.source:
|
||
from ..models import ObjectInfo, ObjectOwnership
|
||
try:
|
||
tv_type = ObjectInfo.objects.get(name="Стационарные")
|
||
tv_ownership = ObjectOwnership.objects.get(name="ТВ")
|
||
|
||
# Update source if not already set
|
||
if not objitem.source.info:
|
||
objitem.source.info = tv_type
|
||
if not objitem.source.ownership:
|
||
objitem.source.ownership = tv_ownership
|
||
|
||
objitem.source.save(update_fields=['info', 'ownership'])
|
||
except (ObjectInfo.DoesNotExist, ObjectOwnership.DoesNotExist):
|
||
# If types don't exist, skip this step
|
||
pass
|
||
|
||
linked_count += 1
|
||
|
||
messages.success(
|
||
self.request,
|
||
f"Привязано {linked_count} из {total_count} объектов к источникам LyngSat"
|
||
)
|
||
return redirect("mainapp:link_lyngsat")
|
||
|
||
def form_invalid(self, form):
|
||
return self.render_to_response(self.get_context_data(form=form))
|
||
|
||
|
||
class FillLyngsatDataView(LoginRequiredMixin, FormMessageMixin, FormView):
|
||
"""
|
||
View for filling data from Lyngsat.
|
||
|
||
Allows selecting satellites and regions for parsing data from Lyngsat website.
|
||
Starts asynchronous Celery task for processing.
|
||
"""
|
||
template_name = "mainapp/fill_lyngsat_data.html"
|
||
form_class = FillLyngsatDataForm
|
||
success_url = reverse_lazy("mainapp:lyngsat_task_status")
|
||
error_message = "Форма заполнена некорректно"
|
||
|
||
def form_valid(self, form):
|
||
satellites = form.cleaned_data["satellites"]
|
||
regions = form.cleaned_data["regions"]
|
||
use_cache = form.cleaned_data.get("use_cache", True)
|
||
force_refresh = form.cleaned_data.get("force_refresh", False)
|
||
|
||
# Get satellite names
|
||
target_sats = [sat.name for sat in satellites]
|
||
|
||
try:
|
||
from lyngsatapp.tasks import fill_lyngsat_data_task
|
||
|
||
# Start asynchronous task with caching parameters
|
||
task = fill_lyngsat_data_task.delay(
|
||
target_sats,
|
||
regions,
|
||
force_refresh=force_refresh,
|
||
use_cache=use_cache
|
||
)
|
||
|
||
cache_status = "без кеша" if not use_cache else ("с обновлением кеша" if force_refresh else "с кешированием")
|
||
|
||
messages.success(
|
||
self.request,
|
||
f"Задача запущена ({cache_status})! ID задачи: {task.id}. "
|
||
"Вы будете перенаправлены на страницу отслеживания прогресса."
|
||
)
|
||
|
||
# Redirect to task status page
|
||
return redirect('mainapp:lyngsat_task_status', task_id=task.id)
|
||
|
||
except Exception as e:
|
||
messages.error(self.request, f"Ошибка при запуске задачи: {str(e)}")
|
||
return redirect("mainapp:fill_lyngsat_data")
|
||
|
||
|
||
class LyngsatTaskStatusView(LoginRequiredMixin, View):
|
||
"""View for tracking Lyngsat data filling task status."""
|
||
|
||
template_name = "mainapp/lyngsat_task_status.html"
|
||
|
||
def get(self, request, task_id=None):
|
||
context = {
|
||
'task_id': task_id
|
||
}
|
||
return render(request, self.template_name, context)
|
||
|
||
|
||
class ClearLyngsatCacheView(LoginRequiredMixin, View):
|
||
"""View for clearing LyngSat cache."""
|
||
|
||
def post(self, request):
|
||
from lyngsatapp.tasks import clear_cache_task
|
||
|
||
cache_type = request.POST.get('cache_type', 'all')
|
||
|
||
try:
|
||
# Start cache clearing task
|
||
task = clear_cache_task.delay(cache_type)
|
||
|
||
messages.success(
|
||
request,
|
||
f"Задача очистки кеша ({cache_type}) запущена! ID задачи: {task.id}"
|
||
)
|
||
except Exception as e:
|
||
messages.error(request, f"Ошибка при запуске задачи очистки кеша: {str(e)}")
|
||
|
||
return redirect(request.META.get('HTTP_REFERER', 'mainapp:source_list'))
|
||
|
||
def get(self, request):
|
||
"""Cache management page."""
|
||
return render(request, 'mainapp/clear_lyngsat_cache.html')
|
||
|
||
|
||
class UnlinkAllLyngsatSourcesView(LoginRequiredMixin, View):
|
||
"""View for unlinking all LyngSat sources from ObjItems."""
|
||
|
||
def post(self, request):
|
||
"""Unlink all LyngSat sources."""
|
||
try:
|
||
# Count objects with LyngSat sources before unlinking
|
||
linked_count = ObjItem.objects.filter(lyngsat_source__isnull=False).count()
|
||
|
||
# Unlink all LyngSat sources
|
||
ObjItem.objects.filter(lyngsat_source__isnull=False).update(lyngsat_source=None)
|
||
|
||
messages.success(
|
||
request,
|
||
f"Успешно отвязано {linked_count} объектов от источников LyngSat"
|
||
)
|
||
except Exception as e:
|
||
messages.error(request, f"Ошибка при отвязке источников: {str(e)}")
|
||
|
||
return redirect('mainapp:actions')
|
||
|
||
def get(self, request):
|
||
"""Show confirmation page."""
|
||
# Count objects with LyngSat sources
|
||
linked_count = ObjItem.objects.filter(lyngsat_source__isnull=False).count()
|
||
|
||
context = {
|
||
'linked_count': linked_count
|
||
}
|
||
return render(request, 'mainapp/unlink_lyngsat_confirm.html', context)
|