From d0a53e251ec12c7b663621bad098fc110759bf06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=BE=D1=88=D0=BA=D0=B8=D0=BD=20=D0=A1=D0=B5=D1=80?= =?UTF-8?q?=D0=B3=D0=B5=D0=B9?= Date: Thu, 13 Nov 2025 14:21:02 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D0=B4=D0=B5=D0=BB?= =?UTF-8?q?=D0=B0=D0=BB=20=D1=81=D1=82=D1=80=D0=B0=D0=BD=D0=B8=D1=86=D1=83?= =?UTF-8?q?=20=D1=81=20ObjItem.=20=D0=A2=D0=B5=D0=BF=D0=B5=D1=80=D1=8C=20?= =?UTF-8?q?=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B0=D0=B5=D1=82=20=D0=BA=D0=BE?= =?UTF-8?q?=D1=80=D1=80=D0=B5=D0=BA=D1=82=D0=BD=D0=BE.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dbapp/fix_objitems_without_source.py | 189 +++++++++------- .../components/_column_toggle_item.html | 13 ++ .../_column_visibility_dropdown.html | 44 ++++ .../templates/mainapp/components/_navbar.html | 2 +- .../templates/mainapp/objitem_list.html | 205 +----------------- dbapp/mainapp/urls.py | 6 +- dbapp/mainapp/utils.py | 66 ++---- dbapp/mainapp/views.py | 37 +--- 8 files changed, 204 insertions(+), 358 deletions(-) create mode 100644 dbapp/mainapp/templates/mainapp/components/_column_toggle_item.html create mode 100644 dbapp/mainapp/templates/mainapp/components/_column_visibility_dropdown.html diff --git a/dbapp/fix_objitems_without_source.py b/dbapp/fix_objitems_without_source.py index c1a6aea..e8ab7fd 100644 --- a/dbapp/fix_objitems_without_source.py +++ b/dbapp/fix_objitems_without_source.py @@ -8,92 +8,121 @@ 4. Иначе создать новый Source с coords_average = координаты geo_obj """ -import os -import django +# import os +# import django -os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dbapp.settings") -django.setup() +# os.environ.setdefault("DJANGO_SETTINGS_MODULE", "dbapp.settings") +# django.setup() -from mainapp.models import ObjItem, Source, CustomUser -from django.contrib.gis.geos import Point -from django.contrib.gis.measure import D -from django.contrib.gis.db.models.functions import Distance +# from mainapp.models import ObjItem, Source, CustomUser +# from django.contrib.gis.geos import Point +# from django.contrib.gis.measure import D +# from django.contrib.gis.db.models.functions import Distance -def calculate_distance_degrees(coord1, coord2): - """Вычисляет расстояние между двумя координатами в градусах.""" - import math +# def calculate_distance_degrees(coord1, coord2): +# """Вычисляет расстояние между двумя координатами в градусах.""" +# import math +# lon1, lat1 = coord1 +# lon2, lat2 = coord2 + +# return math.sqrt((lon2 - lon1) ** 2 + (lat2 - lat1) ** 2) + + +# def fix_objitems_without_source(): +# """Исправляет ObjItems без связи с Source.""" + +# # Получаем пользователя по умолчанию +# default_user = CustomUser.objects.get(id=1) + +# # Получаем все ObjItems без source +# objitems_without_source = ObjItem.objects.filter(source__isnull=True) +# total_count = objitems_without_source.count() + +# print(f"Найдено {total_count} ObjItems без source") + +# if total_count == 0: +# print("Нечего исправлять!") +# return + +# fixed_count = 0 +# new_sources_count = 0 + +# for objitem in objitems_without_source: +# # Проверяем, есть ли geo_obj +# if not hasattr(objitem, 'geo_obj') or not objitem.geo_obj or not objitem.geo_obj.coords: +# print(f"ObjItem {objitem.id} не имеет geo_obj или координат, пропускаем") +# continue + +# geo_coords = objitem.geo_obj.coords +# coord_tuple = (geo_coords.x, geo_coords.y) + +# # Ищем ближайший Source +# sources_with_coords = Source.objects.filter(coords_average__isnull=False) + +# closest_source = None +# min_distance = float('inf') + +# for source in sources_with_coords: +# source_coord = (source.coords_average.x, source.coords_average.y) +# distance = calculate_distance_degrees(coord_tuple, source_coord) + +# if distance < min_distance: +# min_distance = distance +# closest_source = source + +# # Если нашли близкий Source (расстояние <= 0.5 градуса) +# if closest_source and min_distance <= 0.5: +# objitem.source = closest_source +# objitem.save() +# print(f"ObjItem {objitem.id} связан с Source {closest_source.id} (расстояние: {min_distance:.4f}°)") +# fixed_count += 1 +# else: +# # Создаем новый Source +# new_source = Source.objects.create( +# coords_average=Point(coord_tuple, srid=4326), +# created_by=default_user +# ) +# objitem.source = new_source +# objitem.save() +# print(f"ObjItem {objitem.id} связан с новым Source {new_source.id}") +# fixed_count += 1 +# new_sources_count += 1 + +# print(f"\nГотово!") +# print(f"Исправлено ObjItems: {fixed_count}") +# print(f"Создано новых Source: {new_sources_count}") + + +# if __name__ == "__main__": +# fix_objitems_without_source() + + +from geographiclib.geodesic import Geodesic + +def calculate_mean_coords(coord1: tuple, coord2: tuple) -> tuple[tuple, float]: + """ + Вычисляет среднюю точку между двумя координатами с использованием геодезических вычислений (с учётом эллипсоида). + + :param lat1: Широта первой точки в градусах. + :param lon1: Долгота первой точки в градусах. + :param lat2: Широта второй точки в градусах. + :param lon2: Долгота второй точки в градусах. + :return: Словарь с ключами 'lat' и 'lon' для средней точки, и расстояние(dist) в КМ. + """ lon1, lat1 = coord1 lon2, lat2 = coord2 - - return math.sqrt((lon2 - lon1) ** 2 + (lat2 - lat1) ** 2) + geod_inv = Geodesic.WGS84.Inverse(lat1, lon1, lat2, lon2) + azimuth1 = geod_inv['azi1'] + distance = geod_inv['s12'] + geod_direct = Geodesic.WGS84.Direct(lat1, lon1, azimuth1, distance / 2) + return (geod_direct['lon2'], geod_direct['lat2']), distance/1000 +# Пример использования +lat1, lon1 = 56.15465080269812, 38.140518028837285 +lat2, lon2 = 56.0852, 38.0852 +midpoint = calculate_mean_coords((lat1, lon1), (lat2, lon2)) #56.15465080269812, 38.140518028837285 -def fix_objitems_without_source(): - """Исправляет ObjItems без связи с Source.""" - - # Получаем пользователя по умолчанию - default_user = CustomUser.objects.get(id=1) - - # Получаем все ObjItems без source - objitems_without_source = ObjItem.objects.filter(source__isnull=True) - total_count = objitems_without_source.count() - - print(f"Найдено {total_count} ObjItems без source") - - if total_count == 0: - print("Нечего исправлять!") - return - - fixed_count = 0 - new_sources_count = 0 - - for objitem in objitems_without_source: - # Проверяем, есть ли geo_obj - if not hasattr(objitem, 'geo_obj') or not objitem.geo_obj or not objitem.geo_obj.coords: - print(f"ObjItem {objitem.id} не имеет geo_obj или координат, пропускаем") - continue - - geo_coords = objitem.geo_obj.coords - coord_tuple = (geo_coords.x, geo_coords.y) - - # Ищем ближайший Source - sources_with_coords = Source.objects.filter(coords_average__isnull=False) - - closest_source = None - min_distance = float('inf') - - for source in sources_with_coords: - source_coord = (source.coords_average.x, source.coords_average.y) - distance = calculate_distance_degrees(coord_tuple, source_coord) - - if distance < min_distance: - min_distance = distance - closest_source = source - - # Если нашли близкий Source (расстояние <= 0.5 градуса) - if closest_source and min_distance <= 0.5: - objitem.source = closest_source - objitem.save() - print(f"ObjItem {objitem.id} связан с Source {closest_source.id} (расстояние: {min_distance:.4f}°)") - fixed_count += 1 - else: - # Создаем новый Source - new_source = Source.objects.create( - coords_average=Point(coord_tuple, srid=4326), - created_by=default_user - ) - objitem.source = new_source - objitem.save() - print(f"ObjItem {objitem.id} связан с новым Source {new_source.id}") - fixed_count += 1 - new_sources_count += 1 - - print(f"\nГотово!") - print(f"Исправлено ObjItems: {fixed_count}") - print(f"Создано новых Source: {new_sources_count}") - - -if __name__ == "__main__": - fix_objitems_without_source() +print(f"Средняя точка: {midpoint[0]}") +print(f"Расстояние: {midpoint[1]} км") \ No newline at end of file diff --git a/dbapp/mainapp/templates/mainapp/components/_column_toggle_item.html b/dbapp/mainapp/templates/mainapp/components/_column_toggle_item.html new file mode 100644 index 0000000..84a444f --- /dev/null +++ b/dbapp/mainapp/templates/mainapp/components/_column_toggle_item.html @@ -0,0 +1,13 @@ +{% comment %} +Компонент для элемента переключения видимости столбца +Использование: + {% include 'mainapp/components/_column_toggle_item.html' with column_index=0 column_label="Выбрать" checked=True %} + {% include 'mainapp/components/_column_toggle_item.html' with column_index=1 column_label="Имя" checked=True %} +{% endcomment %} + +
  • + +
  • \ No newline at end of file diff --git a/dbapp/mainapp/templates/mainapp/components/_column_visibility_dropdown.html b/dbapp/mainapp/templates/mainapp/components/_column_visibility_dropdown.html new file mode 100644 index 0000000..4355541 --- /dev/null +++ b/dbapp/mainapp/templates/mainapp/components/_column_visibility_dropdown.html @@ -0,0 +1,44 @@ +{% comment %} +Компонент для выпадающего списка видимости столбцов +Использование: + {% include 'mainapp/components/_column_visibility_dropdown.html' %} +{% endcomment %} + + \ No newline at end of file diff --git a/dbapp/mainapp/templates/mainapp/components/_navbar.html b/dbapp/mainapp/templates/mainapp/components/_navbar.html index 722ea46..6d3d49d 100644 --- a/dbapp/mainapp/templates/mainapp/components/_navbar.html +++ b/dbapp/mainapp/templates/mainapp/components/_navbar.html @@ -14,7 +14,7 @@ {% if user.is_authenticated %}