Исправил импорт данных с привязкой спутников

This commit is contained in:
2025-12-01 15:48:00 +03:00
parent c72bf12d41
commit 8d75e47abc
7 changed files with 691 additions and 531 deletions

View File

@@ -122,6 +122,72 @@ MINIMUM_BANDWIDTH_MHZ = 0.08
RANGE_DISTANCE = 56
# ============================================================================
# Вспомогательные функции для работы со спутниками
# ============================================================================
class SatelliteNotFoundError(Exception):
"""Исключение, возникающее когда спутник не найден в базе данных."""
pass
def get_satellite_by_norad(norad_id: int) -> Satellite:
"""
Получает спутник по NORAD ID с обработкой ошибок.
Args:
norad_id: NORAD ID спутника
Returns:
Satellite: объект спутника
Raises:
SatelliteNotFoundError: если спутник не найден
ValueError: если norad_id некорректен
"""
if not norad_id or norad_id == -1:
raise ValueError(f"Некорректный NORAD ID: {norad_id}")
try:
return Satellite.objects.get(norad=norad_id)
except Satellite.DoesNotExist:
raise SatelliteNotFoundError(
f"Спутник с NORAD ID {norad_id} не найден в базе данных. "
f"Добавьте спутник в справочник перед импортом данных."
)
except Satellite.MultipleObjectsReturned:
# Если по какой-то причине есть дубликаты, берем первый
return Satellite.objects.filter(norad=norad_id).first()
def get_satellite_by_name(name: str) -> Satellite:
"""
Получает спутник по имени с обработкой ошибок.
Args:
name: имя спутника
Returns:
Satellite: объект спутника
Raises:
SatelliteNotFoundError: если спутник не найден
"""
if not name or name.strip() == "-":
raise ValueError(f"Некорректное имя спутника: {name}")
try:
return Satellite.objects.get(name=name.strip())
except Satellite.DoesNotExist:
raise SatelliteNotFoundError(
f"Спутник '{name}' не найден в базе данных. "
f"Добавьте спутник в справочник перед импортом данных."
)
except Satellite.MultipleObjectsReturned:
# Если есть дубликаты по имени, берем первый
return Satellite.objects.filter(name=name.strip()).first()
def get_all_constants():
sats = [sat.name for sat in Satellite.objects.all()]
standards = [sat.name for sat in Standard.objects.all()]
@@ -307,7 +373,12 @@ def fill_data_from_df(df: pd.DataFrame, sat: Satellite, current_user=None, is_au
is_automatic: если True, точки не добавляются к Source (optional, default=False)
Returns:
int: количество созданных Source (или 0 если is_automatic=True)
dict: словарь с результатами импорта {
'new_sources': количество созданных Source,
'added': количество добавленных точек,
'skipped': количество пропущенных дубликатов,
'errors': список ошибок
}
"""
try:
df.rename(columns={"Модуляция ": "Модуляция"}, inplace=True)
@@ -321,6 +392,7 @@ def fill_data_from_df(df: pd.DataFrame, sat: Satellite, current_user=None, is_au
new_sources_count = 0
added_count = 0
skipped_count = 0
errors = []
# Словарь для кэширования Source в рамках текущего импорта
# Ключ: (имя источника, id Source), Значение: объект Source
@@ -391,13 +463,21 @@ def fill_data_from_df(df: pd.DataFrame, sat: Satellite, current_user=None, is_au
added_count += 1
except Exception as e:
error_msg = f"Строка {idx + 2}: {str(e)}"
print(f"Ошибка при обработке строки {idx}: {e}")
errors.append(error_msg)
continue
print(f"Импорт завершен: создано {new_sources_count} новых источников, "
f"добавлено {added_count} точек, пропущено {skipped_count} дубликатов")
f"добавлено {added_count} точек, пропущено {skipped_count} дубликатов, "
f"ошибок: {len(errors)}")
return new_sources_count
return {
'new_sources': new_sources_count,
'added': added_count,
'skipped': skipped_count,
'errors': errors
}
def _create_objitem_from_row(row, sat, source, user_to_use, consts, is_automatic=False):
@@ -574,6 +654,11 @@ def _create_objitem_from_row(row, sat, source, user_to_use, consts, is_automatic
def add_satellite_list():
"""
Добавляет список спутников в базу данных (если их еще нет).
Примечание: Эта функция устарела. Используйте админ-панель для добавления спутников.
"""
sats = [
"AZERSPACE 2",
"Amos 4",
@@ -673,7 +758,12 @@ def get_points_from_csv(file_content, current_user=None, is_automatic=False):
is_automatic: если True, точки не добавляются к Source (optional, default=False)
Returns:
int: количество созданных Source (или 0 если is_automatic=True)
dict: словарь с результатами импорта {
'new_sources': количество созданных Source,
'added': количество добавленных точек,
'skipped': количество пропущенных дубликатов,
'errors': список ошибок
}
"""
df = pd.read_csv(
io.StringIO(file_content),
@@ -711,6 +801,7 @@ def get_points_from_csv(file_content, current_user=None, is_automatic=False):
new_sources_count = 0
added_count = 0
skipped_count = 0
errors = []
# Словарь для кэширования Source в рамках текущего импорта
# Ключ: (имя источника, имя спутника, id Source), Значение: объект Source
@@ -733,14 +824,15 @@ def get_points_from_csv(file_content, current_user=None, is_automatic=False):
skipped_count += 1
continue
# Получаем или создаем объект спутника
# sat_obj, _ = Satellite.objects.get_or_create(
# name=sat_name, defaults={"norad": row["norad_id"]}
# )
# Получаем объект спутника по NORAD ID
try:
sat_obj = get_satellite_by_norad(row["norad_id"])
except (SatelliteNotFoundError, ValueError) as e:
error_msg = f"Строка {idx + 2}: {str(e)}"
print(error_msg)
errors.append(error_msg)
continue
sat_obj, _ = Satellite.objects.get_or_create(
norad=row["norad_id"], defaults={"name": sat_name}
)
source = None
# Если is_automatic=False, работаем с Source
@@ -785,13 +877,21 @@ def get_points_from_csv(file_content, current_user=None, is_automatic=False):
added_count += 1
except Exception as e:
error_msg = f"Строка {idx + 2}: {str(e)}"
print(f"Ошибка при обработке строки {idx}: {e}")
errors.append(error_msg)
continue
print(f"Импорт завершен: создано {new_sources_count} новых источников, "
f"добавлено {added_count} точек, пропущено {skipped_count} дубликатов")
f"добавлено {added_count} точек, пропущено {skipped_count} дубликатов, "
f"ошибок: {len(errors)}")
return new_sources_count
return {
'new_sources': new_sources_count,
'added': added_count,
'skipped': skipped_count,
'errors': errors
}
def _is_duplicate_by_coords_and_time(coord_tuple, timestamp, tolerance_km=0.001):
@@ -923,9 +1023,12 @@ def _create_objitem_from_csv_row(row, source, user_to_use, is_automatic=False):
pol = "-"
pol_obj, _ = Polarization.objects.get_or_create(name=pol)
sat_obj, _ = Satellite.objects.get_or_create(
name=row["sat"], defaults={"norad": row["norad_id"]}
)
# Получаем объект спутника по NORAD ID
try:
sat_obj = get_satellite_by_norad(row["norad_id"])
except (SatelliteNotFoundError, ValueError) as e:
raise Exception(f"Не удалось получить спутник: {str(e)}")
# Ищем данные в TechAnalyze
tech_data = _find_tech_analyze_data(row["obj"], sat_obj)