305 lines
14 KiB
Python
305 lines
14 KiB
Python
from django.db import models
|
||
from django.contrib.auth.models import User
|
||
from django.contrib.gis.db import models as gis
|
||
from django.contrib.gis.db.models import functions
|
||
from django.db.models import F, ExpressionWrapper
|
||
from django.utils import timezone
|
||
|
||
def get_default_polarization():
|
||
obj, created = Polarization.objects.get_or_create(
|
||
name="-"
|
||
)
|
||
return obj.id
|
||
|
||
def get_default_modulation():
|
||
obj, created = Modulation.objects.get_or_create(
|
||
name="-"
|
||
)
|
||
return obj.id
|
||
|
||
def get_default_standard():
|
||
obj, created = Standard.objects.get_or_create(
|
||
name="-"
|
||
)
|
||
return obj.id
|
||
|
||
class CustomUser(models.Model):
|
||
user = models.OneToOneField(User, on_delete=models.CASCADE)
|
||
ROLE_CHOICES = [
|
||
('admin', 'Администратор'),
|
||
('moderator', 'Модератор'),
|
||
('user', 'Пользователь'),
|
||
]
|
||
|
||
role = models.CharField(max_length=20, choices=ROLE_CHOICES, default='user', verbose_name='Роль пользователя')
|
||
|
||
|
||
def __str__(self):
|
||
return f"{self.user.first_name} {self.user.last_name}" if self.user.first_name and self.user.last_name else self.user.username
|
||
|
||
class Meta:
|
||
verbose_name = "Пользователь"
|
||
verbose_name_plural = "Пользователи"
|
||
|
||
class SigmaParMark(models.Model):
|
||
mark = models.BooleanField(null=True, blank=True, verbose_name="Наличие сигнала")
|
||
timestamp = models.DateTimeField(null=True, blank=True, verbose_name="Время")
|
||
|
||
def __str__(self):
|
||
timestamp = self.timestamp.strftime("%d.%m.%Y %H:%M")
|
||
return f'+ {timestamp}' if self.mark else f'- {timestamp}'
|
||
|
||
class Meta:
|
||
verbose_name = "Отметка"
|
||
verbose_name_plural = "Отметки"
|
||
|
||
|
||
class Mirror(models.Model):
|
||
name = models.CharField(max_length=30, unique=True, verbose_name="Имя зеркала")
|
||
|
||
def __str__(self):
|
||
return self.name
|
||
|
||
class Meta:
|
||
verbose_name = "Зеркало"
|
||
verbose_name_plural = "Зеркала"
|
||
|
||
class Polarization(models.Model):
|
||
name = models.CharField(max_length=20, unique=True, verbose_name="Поляризация")
|
||
|
||
def __str__(self):
|
||
return self.name
|
||
|
||
class Meta:
|
||
verbose_name = "Поляризация"
|
||
verbose_name_plural = "Поляризация"
|
||
|
||
|
||
class Modulation(models.Model):
|
||
name = models.CharField(max_length=20, unique=True, verbose_name="Модуляция", db_index=True)
|
||
|
||
def __str__(self):
|
||
return self.name
|
||
|
||
class Meta:
|
||
verbose_name = "Модуляция"
|
||
verbose_name_plural = "Модуляции"
|
||
|
||
|
||
class Standard(models.Model):
|
||
name = models.CharField(max_length=20, unique=True, verbose_name="Стандарт")
|
||
|
||
def __str__(self):
|
||
return self.name
|
||
|
||
class Meta:
|
||
verbose_name = "Стандарт"
|
||
verbose_name_plural = "Стандарты"
|
||
|
||
|
||
class Satellite(models.Model):
|
||
name = models.CharField(max_length=100, unique=True, verbose_name="Имя спутника", db_index=True)
|
||
norad = models.IntegerField(blank=True, null=True, verbose_name="NORAD ID")
|
||
|
||
def __str__(self):
|
||
return self.name
|
||
|
||
class Meta:
|
||
verbose_name = "Спутник"
|
||
verbose_name_plural = "Спутники"
|
||
|
||
|
||
class ObjItem(models.Model):
|
||
name = models.CharField(null=True, blank=True, max_length=100, verbose_name="Имя объекта", db_index=True)
|
||
# id_satellite = models.ForeignKey(Satellite, on_delete=models.PROTECT, related_name="objitems", verbose_name="Спутник")
|
||
# id_vch_load = models.ForeignKey(Parameter, on_delete=models.CASCADE, related_name="objitems", verbose_name="ВЧ загрузка")
|
||
# id_geo = models.ForeignKey(Geo, on_delete=models.CASCADE, related_name="objitems", verbose_name="Геоданные")
|
||
# id_user_add = models.ForeignKey(CustomUser, on_delete=models.SET_NULL, related_name="objitems", verbose_name="Пользователь", null=True, blank=True)
|
||
# id_source_type = models.ForeignKey(SourceType, on_delete=models.SET_NULL, related_name="objitems", verbose_name='Тип источника', null=True, blank=True)
|
||
|
||
created_at = models.DateTimeField(auto_now_add=True, verbose_name="Дата создания")
|
||
created_by = models.ForeignKey(CustomUser, on_delete=models.SET_NULL, related_name="objitems_created",
|
||
null=True, blank=True, verbose_name="Создан пользователем")
|
||
updated_at = models.DateTimeField(auto_now=True, verbose_name="Дата последнего изменения")
|
||
updated_by = models.ForeignKey(CustomUser, on_delete=models.SET_NULL, related_name="objitems_updated",
|
||
null=True, blank=True, verbose_name="Изменен пользователем")
|
||
|
||
|
||
def __str__(self):
|
||
return f"Объект {self.name}"
|
||
|
||
class Meta:
|
||
verbose_name = "Объект"
|
||
verbose_name_plural = "Объекты"
|
||
# constraints = [
|
||
# models.UniqueConstraint(
|
||
# fields=['id_vch_load', 'id_geo'],
|
||
# name='unique_objitem_combination'
|
||
# )
|
||
# ]
|
||
|
||
class SourceType(models.Model):
|
||
name = models.CharField(max_length=50, unique=True, verbose_name="Тип источника")
|
||
objitem = models.OneToOneField(ObjItem, on_delete=models.SET_NULL, verbose_name="Гео", related_name="source_type_obj", null=True)
|
||
|
||
def __str__(self):
|
||
return self.name
|
||
|
||
class Meta:
|
||
verbose_name = "Тип источника"
|
||
verbose_name_plural = 'Типы источников'
|
||
|
||
|
||
class Parameter(models.Model):
|
||
id_satellite = models.ForeignKey(Satellite, on_delete=models.PROTECT, related_name="parameters", verbose_name="Спутник", null=True)
|
||
polarization = models.ForeignKey(
|
||
Polarization, default=get_default_polarization, on_delete=models.SET_DEFAULT, related_name="polarizations", null=True, blank=True, verbose_name="Поляризация"
|
||
)
|
||
frequency = models.FloatField(default=0, null=True, blank=True, verbose_name="Частота, МГц", db_index=True)
|
||
freq_range = models.FloatField(default=0, null=True, blank=True, verbose_name="Полоса частот, МГц")
|
||
bod_velocity = models.FloatField(default=0, null=True, blank=True, verbose_name="Символьная скорость, БОД")
|
||
modulation = models.ForeignKey(
|
||
Modulation, default=get_default_modulation, on_delete=models.SET_DEFAULT, related_name="modulations", null=True, blank=True, verbose_name="Модуляция"
|
||
)
|
||
snr = models.FloatField(default=0, null=True, blank=True, verbose_name="ОСШ")
|
||
standard = models.ForeignKey(
|
||
Standard, default=get_default_standard, on_delete=models.SET_DEFAULT, related_name="standards", null=True, blank=True, verbose_name="Стандарт"
|
||
)
|
||
id_user_add = models.ForeignKey(CustomUser, on_delete=models.SET_NULL, related_name="parameter_added", verbose_name="Пользователь", null=True, blank=True)
|
||
objitems = models.ManyToManyField(ObjItem, related_name="parameters_obj", verbose_name="Источники", blank=True)
|
||
# id_sigma_parameter = models.ManyToManyField(SigmaParameter, on_delete=models.SET_NULL, related_name="sigma_parameter", verbose_name="ВЧ с sigma", null=True, blank=True)
|
||
# id_sigma_parameter = models.ManyToManyField(SigmaParameter, verbose_name="ВЧ с sigma", null=True, blank=True)
|
||
|
||
|
||
def __str__(self):
|
||
polarization_name = self.polarization.name if self.polarization else "-"
|
||
modulation_name = self.modulation.name if self.modulation else "-"
|
||
return f"Источник-{self.frequency}:{self.freq_range} МГц:{polarization_name}:{modulation_name}"
|
||
|
||
class Meta:
|
||
verbose_name = "ВЧ загрузка"
|
||
verbose_name_plural = "ВЧ загрузки"
|
||
indexes = [
|
||
models.Index(fields=['id_satellite', 'frequency']),
|
||
models.Index(fields=['frequency', 'polarization']),
|
||
]
|
||
# constraints = [
|
||
# models.UniqueConstraint(
|
||
# fields=[
|
||
# 'polarization', 'frequency', 'freq_range',
|
||
# 'bod_velocity', 'modulation', 'snr', 'standard'
|
||
# ],
|
||
# name='unique_parameter_combination'
|
||
# )
|
||
# ]
|
||
|
||
|
||
class SigmaParameter(models.Model):
|
||
TRANSFERS = [
|
||
(-1.0, "-"),
|
||
(9750.0, "9750 МГц"),
|
||
(10750.0, "10750 МГц")
|
||
]
|
||
|
||
id_satellite = models.ForeignKey(Satellite, on_delete=models.PROTECT, related_name="sigmapar_sat", verbose_name="Спутник")
|
||
transfer = models.FloatField(
|
||
choices=TRANSFERS,
|
||
default=-1.0,
|
||
verbose_name="Перенос по частоте"
|
||
)
|
||
status = models.CharField(max_length=20, blank=True, null=True, verbose_name="Статус")
|
||
frequency = models.FloatField(default=0, null=True, blank=True, verbose_name="Частота, МГц", db_index=True)
|
||
transfer_frequency = models.GeneratedField(
|
||
expression=ExpressionWrapper(
|
||
F('frequency') + F('transfer'),
|
||
output_field=models.FloatField()
|
||
),
|
||
output_field=models.FloatField(),
|
||
db_persist=True,
|
||
null=True, blank=True, verbose_name="Частота в Ku, МГц"
|
||
)
|
||
freq_range = models.FloatField(default=0, null=True, blank=True, verbose_name="Полоса частот, МГц")
|
||
power = models.FloatField(default=0, null=True, blank=True, verbose_name="Мощность, дБм")
|
||
bod_velocity = models.FloatField(default=0, null=True, blank=True, verbose_name="Символьная скорость, БОД")
|
||
polarization = models.ForeignKey(
|
||
Polarization, default=get_default_polarization, on_delete=models.SET_DEFAULT, related_name="polarizations_sigma", null=True, blank=True, verbose_name="Поляризация"
|
||
)
|
||
modulation = models.ForeignKey(
|
||
Modulation, default=get_default_modulation, on_delete=models.SET_DEFAULT, related_name="modulations_sigma", null=True, blank=True, verbose_name="Модуляция"
|
||
)
|
||
snr = models.FloatField(default=0, null=True, blank=True, verbose_name="ОСШ, Дб")
|
||
standard = models.ForeignKey(
|
||
Standard, default=get_default_standard, on_delete=models.SET_DEFAULT, related_name="standards_sigma", null=True, blank=True, verbose_name="Стандарт"
|
||
)
|
||
packets = models.BooleanField(null=True, blank=True, verbose_name="Пакетность")
|
||
datetime_begin = models.DateTimeField(null=True, blank=True, verbose_name="Время начала измерения")
|
||
datetime_end = models.DateTimeField(null=True, blank=True, verbose_name="Время окончания измерения")
|
||
mark = models.ManyToManyField(SigmaParMark, verbose_name="Отметка", blank=True)
|
||
parameter = models.ForeignKey(
|
||
Parameter,
|
||
on_delete=models.SET_NULL,
|
||
related_name='sigma_parameter',
|
||
verbose_name="ВЧ",
|
||
null=True,
|
||
blank=True
|
||
)
|
||
|
||
def __str__(self):
|
||
modulation_name = self.modulation.name if self.modulation else "-"
|
||
return f"Sigma-{self.frequency}:{self.freq_range} МГц:{modulation_name}"
|
||
|
||
class Meta:
|
||
verbose_name = "ВЧ sigma"
|
||
verbose_name_plural = "ВЧ sigma"
|
||
|
||
class Geo(models.Model):
|
||
mirrors = models.ManyToManyField(Mirror, related_name="geo_mirrors", verbose_name="Зеркала",)
|
||
timestamp = models.DateTimeField(null=True, blank=True, verbose_name="Время", db_index=True)
|
||
coords = gis.PointField(srid=4326, null=True, blank=True, verbose_name="Координата геолокации")
|
||
location = models.CharField(max_length=255, null=True, blank=True, verbose_name="Метоположение")
|
||
comment = models.CharField(max_length=255, blank=True, verbose_name="Комментарий")
|
||
coords_kupsat = gis.PointField(srid=4326, null=True, blank=True, verbose_name="Координаты Кубсата")
|
||
coords_valid = gis.PointField(srid=4326, null=True, blank=True, verbose_name="Координаты оперативников")
|
||
is_average = models.BooleanField(null=True, blank=True, verbose_name="Усреднённое")
|
||
id_user_add = models.ForeignKey(CustomUser, on_delete=models.SET_NULL, related_name="geos_added", verbose_name="Пользователь", null=True, blank=True)
|
||
distance_coords_kup = models.GeneratedField(
|
||
expression=functions.Distance("coords", "coords_kupsat")/1000,
|
||
output_field=models.FloatField(),
|
||
db_persist=True,
|
||
null=True, blank=True, verbose_name="Расстояние между купсатом и гео, км"
|
||
)
|
||
distance_coords_valid = models.GeneratedField(
|
||
expression=functions.Distance("coords", "coords_valid")/1000,
|
||
output_field=models.FloatField(),
|
||
db_persist=True,
|
||
null=True, blank=True, verbose_name="Расстояние между гео и оперативным отделом, км"
|
||
)
|
||
distance_kup_valid = models.GeneratedField(
|
||
expression=functions.Distance("coords_valid", "coords_kupsat")/1000,
|
||
output_field=models.FloatField(),
|
||
db_persist=True,
|
||
null=True, blank=True, verbose_name="Расстояние между купсатом и оперативным отделом, км"
|
||
)
|
||
objitem = models.OneToOneField(ObjItem, on_delete=models.SET_NULL, verbose_name="Гео", related_name="geo_obj", null=True)
|
||
|
||
def __str__(self):
|
||
longitude = self.coords.coords[0]
|
||
latitude = self.coords.coords[1]
|
||
lon = f"{longitude}E" if longitude > 0 else f"{abs(longitude)}W"
|
||
lat = f"{latitude}N" if latitude > 0 else f"{abs(latitude)}S"
|
||
return f"{lat} {lon}, {self.location}"
|
||
|
||
|
||
class Meta:
|
||
verbose_name = "Гео"
|
||
verbose_name_plural = "Гео"
|
||
constraints = [
|
||
models.UniqueConstraint(
|
||
fields=[
|
||
'timestamp', 'coords'
|
||
],
|
||
name='unique_geo_combination'
|
||
)
|
||
]
|
||
|