201 lines
6.9 KiB
Python
201 lines
6.9 KiB
Python
"""
|
||
Модели технического анализа (TechAnalyze, ObjectMark).
|
||
"""
|
||
from django.db import models
|
||
from django.utils import timezone
|
||
|
||
from .defaults import (
|
||
get_default_polarization,
|
||
get_default_modulation,
|
||
get_default_standard,
|
||
)
|
||
|
||
|
||
class TechAnalyze(models.Model):
|
||
"""
|
||
Модель технического анализа сигнала.
|
||
|
||
Хранит информацию о технических параметрах сигнала для анализа.
|
||
"""
|
||
|
||
# Основные поля
|
||
name = models.CharField(
|
||
max_length=255,
|
||
unique=True,
|
||
verbose_name="Имя",
|
||
db_index=True,
|
||
help_text="Уникальное название для технического анализа",
|
||
)
|
||
satellite = models.ForeignKey(
|
||
'mainapp.Satellite',
|
||
on_delete=models.PROTECT,
|
||
related_name="tech_analyzes",
|
||
verbose_name="Спутник",
|
||
help_text="Спутник, к которому относится анализ",
|
||
)
|
||
polarization = models.ForeignKey(
|
||
'mainapp.Polarization',
|
||
default=get_default_polarization,
|
||
on_delete=models.SET_DEFAULT,
|
||
related_name="tech_analyze_polarizations",
|
||
null=True,
|
||
blank=True,
|
||
verbose_name="Поляризация",
|
||
)
|
||
frequency = models.FloatField(
|
||
default=0,
|
||
null=True,
|
||
blank=True,
|
||
verbose_name="Частота, МГц",
|
||
db_index=True,
|
||
help_text="Центральная частота сигнала",
|
||
)
|
||
freq_range = models.FloatField(
|
||
default=0,
|
||
null=True,
|
||
blank=True,
|
||
verbose_name="Полоса частот, МГц",
|
||
help_text="Полоса частот сигнала",
|
||
)
|
||
bod_velocity = models.FloatField(
|
||
default=0,
|
||
null=True,
|
||
blank=True,
|
||
verbose_name="Символьная скорость, БОД",
|
||
help_text="Символьная скорость",
|
||
)
|
||
modulation = models.ForeignKey(
|
||
'mainapp.Modulation',
|
||
default=get_default_modulation,
|
||
on_delete=models.SET_DEFAULT,
|
||
related_name="tech_analyze_modulations",
|
||
null=True,
|
||
blank=True,
|
||
verbose_name="Модуляция",
|
||
)
|
||
standard = models.ForeignKey(
|
||
'mainapp.Standard',
|
||
default=get_default_standard,
|
||
on_delete=models.SET_DEFAULT,
|
||
related_name="tech_analyze_standards",
|
||
null=True,
|
||
blank=True,
|
||
verbose_name="Стандарт",
|
||
)
|
||
note = models.TextField(
|
||
null=True,
|
||
blank=True,
|
||
verbose_name="Примечание",
|
||
help_text="Дополнительные примечания",
|
||
)
|
||
|
||
# Метаданные
|
||
created_at = models.DateTimeField(
|
||
auto_now_add=True,
|
||
verbose_name="Дата создания",
|
||
help_text="Дата и время создания записи",
|
||
)
|
||
created_by = models.ForeignKey(
|
||
'mainapp.CustomUser',
|
||
on_delete=models.SET_NULL,
|
||
related_name="tech_analyze_created",
|
||
null=True,
|
||
blank=True,
|
||
verbose_name="Создан пользователем",
|
||
help_text="Пользователь, создавший запись",
|
||
)
|
||
updated_at = models.DateTimeField(
|
||
auto_now=True,
|
||
verbose_name="Дата последнего изменения",
|
||
help_text="Дата и время последнего изменения",
|
||
)
|
||
updated_by = models.ForeignKey(
|
||
'mainapp.CustomUser',
|
||
on_delete=models.SET_NULL,
|
||
related_name="tech_analyze_updated",
|
||
null=True,
|
||
blank=True,
|
||
verbose_name="Изменен пользователем",
|
||
help_text="Пользователь, последним изменивший запись",
|
||
)
|
||
|
||
def __str__(self):
|
||
return f"{self.name} ({self.satellite.name if self.satellite else '-'})"
|
||
|
||
class Meta:
|
||
verbose_name = "Тех. анализ"
|
||
verbose_name_plural = "Тех. анализы"
|
||
ordering = ["-created_at"]
|
||
|
||
|
||
class ObjectMark(models.Model):
|
||
"""
|
||
Модель отметки о наличии сигнала.
|
||
|
||
Используется для фиксации моментов времени когда сигнал был обнаружен или отсутствовал.
|
||
Привязывается к записям технического анализа (TechAnalyze).
|
||
"""
|
||
|
||
# Основные поля
|
||
mark = models.BooleanField(
|
||
null=True,
|
||
blank=True,
|
||
verbose_name="Наличие сигнала",
|
||
help_text="True - сигнал обнаружен, False - сигнал отсутствует",
|
||
)
|
||
timestamp = models.DateTimeField(
|
||
verbose_name="Время",
|
||
db_index=True,
|
||
help_text="Время фиксации отметки",
|
||
null=True,
|
||
blank=True,
|
||
)
|
||
tech_analyze = models.ForeignKey(
|
||
TechAnalyze,
|
||
on_delete=models.CASCADE,
|
||
related_name="marks",
|
||
verbose_name="Тех. анализ",
|
||
help_text="Связанный технический анализ",
|
||
)
|
||
created_by = models.ForeignKey(
|
||
'mainapp.CustomUser',
|
||
on_delete=models.SET_NULL,
|
||
related_name="marks_created",
|
||
null=True,
|
||
blank=True,
|
||
verbose_name="Создан пользователем",
|
||
help_text="Пользователь, создавший отметку",
|
||
)
|
||
|
||
def can_edit(self):
|
||
"""Проверка возможности редактирования отметки (в течение 5 минут)"""
|
||
from datetime import timedelta
|
||
if not self.timestamp:
|
||
return False
|
||
time_diff = timezone.now() - self.timestamp
|
||
return time_diff < timedelta(minutes=5)
|
||
|
||
def can_add_new_mark_for_object(self):
|
||
"""Проверка возможности добавления новой отметки для объекта (прошло 5 минут с последней)"""
|
||
from datetime import timedelta
|
||
if not self.timestamp:
|
||
return True
|
||
time_diff = timezone.now() - self.timestamp
|
||
return time_diff >= timedelta(minutes=5)
|
||
|
||
def __str__(self):
|
||
if self.timestamp:
|
||
timestamp = self.timestamp.strftime("%d.%m.%Y %H:%M")
|
||
tech_name = self.tech_analyze.name if self.tech_analyze else "?"
|
||
mark_str = "+" if self.mark else "-"
|
||
return f"{tech_name}: {mark_str} {timestamp}"
|
||
return "Отметка без времени"
|
||
|
||
class Meta:
|
||
verbose_name = "Отметка сигнала"
|
||
verbose_name_plural = "Отметки сигналов"
|
||
ordering = ["-timestamp"]
|
||
indexes = [
|
||
models.Index(fields=["tech_analyze", "-timestamp"]),
|
||
]
|