Добавил объединение источников. Вернул норм карту. Удалил ненужные либы

This commit is contained in:
2025-11-26 10:33:07 +03:00
parent 388753ba31
commit 609fd5a1da
10 changed files with 785 additions and 1100 deletions

View File

@@ -34,7 +34,7 @@ from .lyngsat import (
ClearLyngsatCacheView,
UnlinkAllLyngsatSourcesView,
)
from .source import SourceListView, SourceCreateView, SourceUpdateView, SourceDeleteView, DeleteSelectedSourcesView
from .source import SourceListView, SourceCreateView, SourceUpdateView, SourceDeleteView, DeleteSelectedSourcesView, MergeSourcesView
from .transponder import (
TransponderListView,
TransponderCreateView,
@@ -53,7 +53,7 @@ from .map import (
ShowSourcesMapView,
ShowSourceWithPointsMapView,
ShowSourceAveragingStepsMapView,
ClusterTestView,
# ClusterTestView,
)
from .kubsat import (
KubsatView,
@@ -101,6 +101,7 @@ __all__ = [
'SourceUpdateView',
'SourceDeleteView',
'DeleteSelectedSourcesView',
'MergeSourcesView',
# Transponder
'TransponderListView',
'TransponderCreateView',
@@ -117,7 +118,7 @@ __all__ = [
'ShowSourcesMapView',
'ShowSourceWithPointsMapView',
'ShowSourceAveragingStepsMapView',
'ClusterTestView',
# 'ClusterTestView',
# Kubsat
'KubsatView',
'KubsatExportView',

View File

@@ -11,7 +11,7 @@ from django.shortcuts import redirect, render
from django.utils.decorators import method_decorator
from django.views import View
from ..clusters import get_clusters
# from ..clusters import get_clusters
from ..mixins import RoleRequiredMixin
from ..models import ObjItem
@@ -418,19 +418,19 @@ class ShowSourceAveragingStepsMapView(LoginRequiredMixin, View):
return render(request, "mainapp/source_averaging_map.html", context)
class ClusterTestView(LoginRequiredMixin, View):
"""Test view for clustering functionality."""
# class ClusterTestView(LoginRequiredMixin, View):
# """Test view for clustering functionality."""
def get(self, request):
objs = ObjItem.objects.filter(
name__icontains="! Astra 4A 12654,040 [1,962] МГц H"
)
coords = []
for obj in objs:
if hasattr(obj, "geo_obj") and 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)
# def get(self, request):
# objs = ObjItem.objects.filter(
# name__icontains="! Astra 4A 12654,040 [1,962] МГц H"
# )
# coords = []
# for obj in objs:
# if hasattr(obj, "geo_obj") and 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": "ок"})
# return JsonResponse({"success": "ок"})

View File

@@ -980,3 +980,120 @@ class DeleteSelectedSourcesView(LoginRequiredMixin, AdminModeratorMixin, View):
except Exception as e:
return JsonResponse({"error": f"Ошибка при удалении: {str(e)}"}, status=500)
class MergeSourcesView(LoginRequiredMixin, AdminModeratorMixin, View):
"""View for merging multiple sources into one."""
def post(self, request):
"""Merge selected sources into the first one."""
try:
# Parse JSON body
import json
data = json.loads(request.body)
source_ids = data.get('source_ids', [])
info_id = data.get('info_id')
ownership_id = data.get('ownership_id')
note = data.get('note', '')
# Validate input
if not source_ids or len(source_ids) < 2:
return JsonResponse({
'success': False,
'error': 'Необходимо выбрать минимум 2 источника для объединения'
}, status=400)
if not info_id:
return JsonResponse({
'success': False,
'error': 'Необходимо выбрать тип объекта'
}, status=400)
if not ownership_id:
return JsonResponse({
'success': False,
'error': 'Необходимо выбрать принадлежность объекта'
}, status=400)
# Get all sources
sources = Source.objects.filter(id__in=source_ids).order_by('id')
if sources.count() != len(source_ids):
return JsonResponse({
'success': False,
'error': 'Некоторые источники не найдены'
}, status=404)
# First source is the target
target_source = sources.first()
sources_to_merge = sources.exclude(id=target_source.id)
# Get ObjectInfo and ObjectOwnership
from ..models import ObjectInfo, ObjectOwnership
try:
info = ObjectInfo.objects.get(id=info_id)
ownership = ObjectOwnership.objects.get(id=ownership_id)
except (ObjectInfo.DoesNotExist, ObjectOwnership.DoesNotExist):
return JsonResponse({
'success': False,
'error': 'Тип объекта или принадлежность не найдены'
}, status=404)
# Start transaction
from django.db import transaction
with transaction.atomic():
# Update target source
target_source.info = info
target_source.ownership = ownership
target_source.note = note
if hasattr(request.user, 'customuser'):
target_source.updated_by = request.user.customuser
target_source.save()
# Move all ObjItems from sources_to_merge to target_source
total_moved = 0
for source in sources_to_merge:
# Get all objitems for this source
objitems = source.source_objitems.all()
objitem_count = objitems.count()
# Update source field for all objitems
objitems.update(source=target_source)
total_moved += objitem_count
# Recalculate coords_average for target source
target_source._recalculate_average_coords()
target_source.update_confirm_at()
target_source.save()
# Delete sources_to_merge (without cascade deleting objitems since we moved them)
# We need to delete marks first (they have CASCADE)
from ..models import ObjectMark
ObjectMark.objects.filter(source__in=sources_to_merge).delete()
# Now delete the sources
deleted_count = sources_to_merge.count()
sources_to_merge.delete()
return JsonResponse({
'success': True,
'message': f'Успешно объединено {deleted_count + 1} источников. Перемещено {total_moved} точек в источник #{target_source.id}',
'target_source_id': target_source.id,
'moved_objitems': total_moved,
'deleted_sources': deleted_count
})
except json.JSONDecodeError:
return JsonResponse({
'success': False,
'error': 'Неверный формат данных'
}, status=400)
except Exception as e:
return JsonResponse({
'success': False,
'error': f'Ошибка при объединении источников: {str(e)}'
}, status=500)