Процесс переделки

This commit is contained in:
2025-11-12 17:53:25 +03:00
parent 73ce06deec
commit 7126974aed
21 changed files with 1927 additions and 1922 deletions

View File

@@ -1,37 +1,30 @@
# Generated by Django 5.2.7 on 2025-11-10 20:03 # Generated by Django 5.2.7 on 2025-11-12 14:21
import django.db.models.deletion from django.db import migrations, models
import mainapp.models
from django.db import migrations, models
class Migration(migrations.Migration):
class Migration(migrations.Migration): initial = True
initial = True dependencies = [
]
dependencies = [
('mainapp', '0007_remove_parameter_objitems_parameter_objitem'), operations = [
] migrations.CreateModel(
name='LyngSat',
operations = [ fields=[
migrations.CreateModel( ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
name='LyngSat', ('frequency', models.FloatField(blank=True, default=0, null=True, verbose_name='Частота, МГц')),
fields=[ ('sym_velocity', models.FloatField(blank=True, default=0, null=True, verbose_name='Символьная скорость, БОД')),
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('last_update', models.DateTimeField(blank=True, null=True, verbose_name='Дата посленего обновления')),
('frequency', models.FloatField(blank=True, default=0, null=True, verbose_name='Частота, МГц')), ('channel_info', models.CharField(blank=True, max_length=20, null=True, verbose_name='Описание источника')),
('sym_velocity', models.FloatField(blank=True, default=0, null=True, verbose_name='Символьная скорость, БОД')), ('fec', models.CharField(blank=True, max_length=30, null=True, verbose_name='Коэффициент коррекции ошибок')),
('last_update', models.DateTimeField(blank=True, null=True, verbose_name='Время')), ('url', models.URLField(blank=True, null=True, verbose_name='Ссылка на страницу')),
('channel_info', models.CharField(blank=True, max_length=20, null=True, verbose_name='Описание источника')), ],
('fec', models.CharField(blank=True, max_length=30, null=True, verbose_name='Коэффициент коррекции ошибок')), options={
('url', models.URLField(blank=True, null=True, verbose_name='Ссылка на страницу')), 'verbose_name': 'Источник LyngSat',
('id_satellite', models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='lyngsat', to='mainapp.satellite', verbose_name='Спутник')), 'verbose_name_plural': 'Источники LyngSat',
('modulation', models.ForeignKey(blank=True, default=mainapp.models.get_default_modulation, null=True, on_delete=django.db.models.deletion.SET_DEFAULT, related_name='lyngsat', to='mainapp.modulation', verbose_name='Модуляция')), },
('polarization', models.ForeignKey(blank=True, default=mainapp.models.get_default_polarization, null=True, on_delete=django.db.models.deletion.SET_DEFAULT, related_name='lyngsat', to='mainapp.polarization', verbose_name='Поляризация')), ),
('standard', models.ForeignKey(blank=True, default=mainapp.models.get_default_standard, null=True, on_delete=django.db.models.deletion.SET_DEFAULT, related_name='lyngsat', to='mainapp.standard', verbose_name='Стандарт')), ]
],
options={
'verbose_name': 'Источник LyngSat',
'verbose_name_plural': 'Источники LyngSat',
},
),
]

View File

@@ -1,18 +0,0 @@
# Generated by Django 5.2.7 on 2025-11-11 13:59
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('lyngsatapp', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='lyngsat',
name='last_update',
field=models.DateTimeField(blank=True, null=True, verbose_name='Дата посленего обновления'),
),
]

View File

@@ -0,0 +1,38 @@
# Generated by Django 5.2.7 on 2025-11-12 14:21
import django.db.models.deletion
import mainapp.models
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
('lyngsatapp', '0001_initial'),
('mainapp', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='lyngsat',
name='id_satellite',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='lyngsat', to='mainapp.satellite', verbose_name='Спутник'),
),
migrations.AddField(
model_name='lyngsat',
name='modulation',
field=models.ForeignKey(blank=True, default=mainapp.models.get_default_modulation, null=True, on_delete=django.db.models.deletion.SET_DEFAULT, related_name='lyngsat', to='mainapp.modulation', verbose_name='Модуляция'),
),
migrations.AddField(
model_name='lyngsat',
name='polarization',
field=models.ForeignKey(blank=True, default=mainapp.models.get_default_polarization, null=True, on_delete=django.db.models.deletion.SET_DEFAULT, related_name='lyngsat', to='mainapp.polarization', verbose_name='Поляризация'),
),
migrations.AddField(
model_name='lyngsat',
name='standard',
field=models.ForeignKey(blank=True, default=mainapp.models.get_default_standard, null=True, on_delete=django.db.models.deletion.SET_DEFAULT, related_name='lyngsat', to='mainapp.standard', verbose_name='Стандарт'),
),
]

File diff suppressed because it is too large Load Diff

View File

@@ -1,204 +1,211 @@
# Generated by Django 5.2.7 on 2025-10-31 13:36 # Generated by Django 5.2.7 on 2025-11-12 14:21
import django.contrib.gis.db.models.fields import django.contrib.gis.db.models.fields
import django.contrib.gis.db.models.functions import django.core.validators
import django.db.models.deletion import django.db.models.deletion
import django.db.models.expressions import django.db.models.expressions
import mainapp.models from django.conf import settings
from django.conf import settings from django.db import migrations, models
from django.db import migrations, models
class Migration(migrations.Migration):
class Migration(migrations.Migration):
initial = True
initial = True
dependencies = [
dependencies = [ ('lyngsatapp', '0001_initial'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL), migrations.swappable_dependency(settings.AUTH_USER_MODEL),
] ]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='Mirror', name='Band',
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=30, unique=True, verbose_name='Имя зеркала')), ('name', models.CharField(help_text='Название диапазона', max_length=50, unique=True, verbose_name='Название')),
], ('border_start', models.FloatField(blank=True, null=True, verbose_name='Нижняя граница диапазона, МГц')),
options={ ('border_end', models.FloatField(blank=True, null=True, verbose_name='Верхняя граница диапазона, МГц')),
'verbose_name': 'Зеркало', ],
'verbose_name_plural': 'Зеркала', options={
}, 'verbose_name': 'Диапазон',
), 'verbose_name_plural': 'Диапазоны',
migrations.CreateModel( 'ordering': ['name'],
name='Modulation', },
fields=[ ),
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), migrations.CreateModel(
('name', models.CharField(db_index=True, max_length=20, unique=True, verbose_name='Модуляция')), name='Mirror',
], fields=[
options={ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
'verbose_name': 'Модуляция', ('name', models.CharField(db_index=True, help_text='Уникальное название зеркала антенны', max_length=30, unique=True, verbose_name='Имя зеркала')),
'verbose_name_plural': 'Модуляции', ],
}, options={
), 'verbose_name': 'Зеркало',
migrations.CreateModel( 'verbose_name_plural': 'Зеркала',
name='Polarization', 'ordering': ['name'],
fields=[ },
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ),
('name', models.CharField(max_length=20, unique=True, verbose_name='Поляризация')), migrations.CreateModel(
], name='Modulation',
options={ fields=[
'verbose_name': 'Поляризация', ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
'verbose_name_plural': 'Поляризация', ('name', models.CharField(db_index=True, help_text='Тип модуляции сигнала (QPSK, 8PSK, 16APSK и т.д.)', max_length=20, unique=True, verbose_name='Модуляция')),
}, ],
), options={
migrations.CreateModel( 'verbose_name': 'Модуляция',
name='Satellite', 'verbose_name_plural': 'Модуляции',
fields=[ 'ordering': ['name'],
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), },
('name', models.CharField(db_index=True, max_length=100, unique=True, verbose_name='Имя спутника')), ),
('norad', models.IntegerField(blank=True, null=True, verbose_name='NORAD ID')), migrations.CreateModel(
], name='Parameter',
options={ fields=[
'verbose_name': 'Спутник', ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
'verbose_name_plural': 'Спутники', ('frequency', models.FloatField(blank=True, db_index=True, default=0, help_text='Центральная частота сигнала', null=True, verbose_name='Частота, МГц')),
}, ('freq_range', models.FloatField(blank=True, default=0, help_text='Полоса частот сигнала', null=True, verbose_name='Полоса частот, МГц')),
), ('bod_velocity', models.FloatField(blank=True, default=0, help_text='Символьная скорость должна быть положительной', null=True, verbose_name='Символьная скорость, БОД')),
migrations.CreateModel( ('snr', models.FloatField(blank=True, default=0, help_text='Отношение сигнал/шум', null=True, verbose_name='ОСШ')),
name='SigmaParMark', ],
fields=[ options={
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 'verbose_name': 'ВЧ загрузка',
('mark', models.BooleanField(blank=True, null=True, verbose_name='Наличие сигнала')), 'verbose_name_plural': 'ВЧ загрузки',
('timestamp', models.DateTimeField(blank=True, null=True, verbose_name='Время')), },
], ),
options={ migrations.CreateModel(
'verbose_name': 'Отметка', name='Polarization',
'verbose_name_plural': 'Отметки', fields=[
}, ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
), ('name', models.CharField(db_index=True, help_text='Тип поляризации (H - горизонтальная, V - вертикальная, L - левая круговая, R - правая круговая)', max_length=20, unique=True, verbose_name='Поляризация')),
migrations.CreateModel( ],
name='Standard', options={
fields=[ 'verbose_name': 'Поляризация',
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 'verbose_name_plural': 'Поляризация',
('name', models.CharField(max_length=20, unique=True, verbose_name='Стандарт')), 'ordering': ['name'],
], },
options={ ),
'verbose_name': 'Стандарт', migrations.CreateModel(
'verbose_name_plural': 'Стандарты', name='Satellite',
}, fields=[
), ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
migrations.CreateModel( ('name', models.CharField(db_index=True, help_text='Название спутника', max_length=100, unique=True, verbose_name='Имя спутника')),
name='CustomUser', ('norad', models.IntegerField(blank=True, help_text='Идентификатор NORAD для отслеживания спутника', null=True, verbose_name='NORAD ID')),
fields=[ ('undersat_point', models.FloatField(blank=True, help_text='Подспутниковая точка в градусах. Восточное полушарие с +, западное с -', null=True, verbose_name='Подспутниковая точка, градусы')),
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('url', models.URLField(blank=True, help_text='Ссылка на сайт, где можно проверить информацию', null=True, verbose_name='Ссылка на источник')),
('role', models.CharField(choices=[('admin', 'Администратор'), ('moderator', 'Модератор'), ('user', 'Пользователь')], default='user', max_length=20, verbose_name='Роль пользователя')), ('comment', models.TextField(blank=True, help_text='Любой возможный комменатрий', null=True, verbose_name='Комментарий')),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ('launch_date', models.DateField(blank=True, help_text='Дата запуска спутника', null=True, verbose_name='Дата запуска')),
], ('created_at', models.DateTimeField(auto_now_add=True, help_text='Дата и время создания записи', verbose_name='Дата создания')),
options={ ('updated_at', models.DateTimeField(auto_now=True, help_text='Дата и время последнего изменения', verbose_name='Дата последнего изменения')),
'verbose_name': 'Пользователь', ],
'verbose_name_plural': 'Пользователи', options={
}, 'verbose_name': 'Спутник',
), 'verbose_name_plural': 'Спутники',
migrations.CreateModel( 'ordering': ['name'],
name='ObjItem', },
fields=[ ),
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), migrations.CreateModel(
('name', models.CharField(blank=True, db_index=True, max_length=100, null=True, verbose_name='Имя объекта')), name='SigmaParameter',
('id_user_add', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='objitems', to='mainapp.customuser', verbose_name='Пользователь')), fields=[
], ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
options={ ('transfer', models.FloatField(choices=[(-1.0, '-'), (9750.0, '9750 МГц'), (10750.0, '10750 МГц')], default=-1.0, help_text='Выберите перенос по частоте', verbose_name='Перенос по частоте')),
'verbose_name': 'Объект', ('status', models.CharField(blank=True, help_text='Статус измерения', max_length=20, null=True, verbose_name='Статус')),
'verbose_name_plural': 'Объекты', ('frequency', models.FloatField(blank=True, db_index=True, default=0, help_text='Центральная частота сигнала', null=True, verbose_name='Частота, МГц')),
}, ('transfer_frequency', models.GeneratedField(db_persist=True, expression=models.ExpressionWrapper(django.db.models.expressions.CombinedExpression(models.F('frequency'), '+', models.F('transfer')), output_field=models.FloatField()), null=True, output_field=models.FloatField(), verbose_name='Частота в Ku, МГц')),
), ('freq_range', models.FloatField(blank=True, default=0, help_text='Полоса частот', null=True, verbose_name='Полоса частот, МГц')),
migrations.CreateModel( ('power', models.FloatField(blank=True, default=0, help_text='Мощность сигнала', null=True, verbose_name='Мощность, дБм')),
name='Parameter', ('bod_velocity', models.FloatField(blank=True, default=0, help_text='Символьная скорость должна быть положительной', null=True, verbose_name='Символьная скорость, БОД')),
fields=[ ('snr', models.FloatField(blank=True, default=0, help_text='Отношение сигнал/шум в диапазоне от -50 до 100 дБ', null=True, validators=[django.core.validators.MinValueValidator(-50), django.core.validators.MaxValueValidator(100)], verbose_name='ОСШ, Дб')),
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('packets', models.BooleanField(blank=True, help_text='Наличие пакетной передачи', null=True, verbose_name='Пакетность')),
('frequency', models.FloatField(blank=True, db_index=True, default=0, null=True, verbose_name='Частота, МГц')), ('datetime_begin', models.DateTimeField(blank=True, help_text='Дата и время начала измерения', null=True, verbose_name='Время начала измерения')),
('freq_range', models.FloatField(blank=True, default=0, null=True, verbose_name='Полоса частот, МГц')), ('datetime_end', models.DateTimeField(blank=True, help_text='Дата и время окончания измерения', null=True, verbose_name='Время окончания измерения')),
('bod_velocity', models.FloatField(blank=True, default=0, null=True, verbose_name='Символьная скорость, БОД')), ],
('snr', models.FloatField(blank=True, default=0, null=True, verbose_name='ОСШ')), options={
('id_user_add', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='parameter_added', to='mainapp.customuser', verbose_name='Пользователь')), 'verbose_name': 'ВЧ sigma',
('modulation', models.ForeignKey(blank=True, default=mainapp.models.get_default_modulation, null=True, on_delete=django.db.models.deletion.SET_DEFAULT, related_name='modulations', to='mainapp.modulation', verbose_name='Модуляция')), 'verbose_name_plural': 'ВЧ sigma',
('objitems', models.ManyToManyField(blank=True, related_name='parameters_obj', to='mainapp.objitem', verbose_name='Источники')), },
('polarization', models.ForeignKey(blank=True, default=mainapp.models.get_default_polarization, null=True, on_delete=django.db.models.deletion.SET_DEFAULT, related_name='polarizations', to='mainapp.polarization', verbose_name='Поляризация')), ),
('id_satellite', models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='parameters', to='mainapp.satellite', verbose_name='Спутник')), migrations.CreateModel(
('standard', models.ForeignKey(blank=True, default=mainapp.models.get_default_standard, null=True, on_delete=django.db.models.deletion.SET_DEFAULT, related_name='standards', to='mainapp.standard', verbose_name='Стандарт')), name='SigmaParMark',
], fields=[
options={ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
'verbose_name': 'ВЧ загрузка', ('mark', models.BooleanField(blank=True, help_text='True - сигнал обнаружен, False - сигнал отсутствует', null=True, verbose_name='Наличие сигнала')),
'verbose_name_plural': 'ВЧ загрузки', ('timestamp', models.DateTimeField(blank=True, db_index=True, help_text='Время фиксации отметки', null=True, verbose_name='Время')),
}, ],
), options={
migrations.CreateModel( 'verbose_name': 'Отметка',
name='SourceType', 'verbose_name_plural': 'Отметки',
fields=[ 'ordering': ['-timestamp'],
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), },
('name', models.CharField(max_length=50, unique=True, verbose_name='Тип источника')), ),
('objitem', models.OneToOneField(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='source_type_obj', to='mainapp.objitem', verbose_name='Гео')), migrations.CreateModel(
], name='Source',
options={ fields=[
'verbose_name': 'Тип источника', ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
'verbose_name_plural': 'Типы источников', ('coords_kupsat', django.contrib.gis.db.models.fields.PointField(blank=True, help_text='Координаты, полученные от кубсата (WGS84)', null=True, srid=4326, verbose_name='Координаты Кубсата')),
}, ('coords_valid', django.contrib.gis.db.models.fields.PointField(blank=True, help_text='Координаты, предоставленные оперативным отделом (WGS84)', null=True, srid=4326, verbose_name='Координаты оперативников')),
), ('coords_reference', django.contrib.gis.db.models.fields.PointField(blank=True, help_text='Координаты, ещё кем-то проверенные (WGS84)', null=True, srid=4326, verbose_name='Координаты справочные')),
migrations.CreateModel( ('created_at', models.DateTimeField(auto_now_add=True, help_text='Дата и время создания записи', verbose_name='Дата создания')),
name='SigmaParameter', ('updated_at', models.DateTimeField(auto_now=True, help_text='Дата и время последнего изменения', verbose_name='Дата последнего изменения')),
fields=[ ],
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), options={
('transfer', models.FloatField(choices=[(-1.0, '-'), (9750.0, '9750 МГц'), (10750.0, '10750 МГц')], default=-1.0, verbose_name='Перенос по частоте')), 'verbose_name': 'Источник',
('status', models.CharField(blank=True, max_length=20, null=True, verbose_name='Статус')), 'verbose_name_plural': 'Источники',
('frequency', models.FloatField(blank=True, db_index=True, default=0, null=True, verbose_name='Частота, МГц')), },
('transfer_frequency', models.GeneratedField(db_persist=True, expression=models.ExpressionWrapper(django.db.models.expressions.CombinedExpression(models.F('frequency'), '+', models.F('transfer')), output_field=models.FloatField()), null=True, output_field=models.FloatField(), verbose_name='Частота в Ku, МГц')), ),
('freq_range', models.FloatField(blank=True, default=0, null=True, verbose_name='Полоса частот, МГц')), migrations.CreateModel(
('power', models.FloatField(blank=True, default=0, null=True, verbose_name='Мощность, дБм')), name='Standard',
('bod_velocity', models.FloatField(blank=True, default=0, null=True, verbose_name='Символьная скорость, БОД')), fields=[
('snr', models.FloatField(blank=True, default=0, null=True, verbose_name='ОСШ, Дб')), ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('packets', models.BooleanField(blank=True, null=True, verbose_name='Пакетность')), ('name', models.CharField(db_index=True, help_text='Стандарт передачи данных (DVB-S, DVB-S2, DVB-S2X и т.д.)', max_length=20, unique=True, verbose_name='Стандарт')),
('datetime_begin', models.DateTimeField(blank=True, null=True, verbose_name='Время начала измерения')), ],
('datetime_end', models.DateTimeField(blank=True, null=True, verbose_name='Время окончания измерения')), options={
('id_satellite', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='sigmapar_sat', to='mainapp.satellite', verbose_name='Спутник')), 'verbose_name': 'Стандарт',
('modulation', models.ForeignKey(blank=True, default=mainapp.models.get_default_modulation, null=True, on_delete=django.db.models.deletion.SET_DEFAULT, related_name='modulations_sigma', to='mainapp.modulation', verbose_name='Модуляция')), 'verbose_name_plural': 'Стандарты',
('parameter', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='sigma_parameter', to='mainapp.parameter', verbose_name='ВЧ')), 'ordering': ['name'],
('polarization', models.ForeignKey(blank=True, default=mainapp.models.get_default_polarization, null=True, on_delete=django.db.models.deletion.SET_DEFAULT, related_name='polarizations_sigma', to='mainapp.polarization', verbose_name='Поляризация')), },
('mark', models.ManyToManyField(blank=True, to='mainapp.sigmaparmark', verbose_name='Отметка')), ),
('standard', models.ForeignKey(blank=True, default=mainapp.models.get_default_standard, null=True, on_delete=django.db.models.deletion.SET_DEFAULT, related_name='standards_sigma', to='mainapp.standard', verbose_name='Стандарт')), migrations.CreateModel(
], name='CustomUser',
options={ fields=[
'verbose_name': 'ВЧ sigma', ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
'verbose_name_plural': 'ВЧ sigma', ('role', models.CharField(choices=[('admin', 'Администратор'), ('moderator', 'Модератор'), ('user', 'Пользователь')], db_index=True, default='user', help_text='Роль пользователя в системе', max_length=20, verbose_name='Роль пользователя')),
}, ('user', models.OneToOneField(help_text='Связанный пользователь Django', on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Пользователь')),
), ],
migrations.CreateModel( options={
name='Geo', 'verbose_name': 'Пользователь',
fields=[ 'verbose_name_plural': 'Пользователи',
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 'ordering': ['user__username'],
('timestamp', models.DateTimeField(blank=True, db_index=True, null=True, verbose_name='Время')), },
('coords', django.contrib.gis.db.models.fields.PointField(blank=True, null=True, srid=4326, verbose_name='Координата геолокации')), ),
('location', models.CharField(blank=True, max_length=255, null=True, verbose_name='Метоположение')), migrations.CreateModel(
('comment', models.CharField(blank=True, max_length=255, verbose_name='Комментарий')), name='Geo',
('coords_kupsat', django.contrib.gis.db.models.fields.PointField(blank=True, null=True, srid=4326, verbose_name='Координаты Кубсата')), fields=[
('coords_valid', django.contrib.gis.db.models.fields.PointField(blank=True, null=True, srid=4326, verbose_name='Координаты оперативников')), ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('is_average', models.BooleanField(blank=True, null=True, verbose_name='Усреднённое')), ('timestamp', models.DateTimeField(blank=True, db_index=True, help_text='Время фиксации геолокации', null=True, verbose_name='Время')),
('distance_coords_kup', models.GeneratedField(db_persist=True, expression=django.db.models.expressions.CombinedExpression(django.contrib.gis.db.models.functions.Distance('coords', 'coords_kupsat'), '/', models.Value(1000)), null=True, output_field=models.FloatField(), verbose_name='Расстояние между купсатом и гео, км')), ('location', models.CharField(blank=True, help_text='Текстовое описание местоположения', max_length=255, null=True, verbose_name='Местоположение')),
('distance_coords_valid', models.GeneratedField(db_persist=True, expression=django.db.models.expressions.CombinedExpression(django.contrib.gis.db.models.functions.Distance('coords', 'coords_valid'), '/', models.Value(1000)), null=True, output_field=models.FloatField(), verbose_name='Расстояние между гео и оперативным отделом, км')), ('comment', models.CharField(blank=True, help_text='Дополнительные комментарии', max_length=255, verbose_name='Комментарий')),
('distance_kup_valid', models.GeneratedField(db_persist=True, expression=django.db.models.expressions.CombinedExpression(django.contrib.gis.db.models.functions.Distance('coords_valid', 'coords_kupsat'), '/', models.Value(1000)), null=True, output_field=models.FloatField(), verbose_name='Расстояние между купсатом и оперативным отделом, км')), ('is_average', models.BooleanField(blank=True, help_text='Является ли координата усредненной', null=True, verbose_name='Усреднённое')),
('id_user_add', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='geos_added', to='mainapp.customuser', verbose_name='Пользователь')), ('coords', django.contrib.gis.db.models.fields.PointField(blank=True, help_text='Основные координаты геолокации (WGS84)', null=True, srid=4326, verbose_name='Координата геолокации')),
('mirrors', models.ManyToManyField(related_name='geo_mirrors', to='mainapp.mirror', verbose_name='Зеркала')), ('mirrors', models.ManyToManyField(blank=True, help_text='Зеркала антенн, использованные для приема', related_name='geo_mirrors', to='mainapp.mirror', verbose_name='Зеркала')),
('objitem', models.OneToOneField(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='geo_obj', to='mainapp.objitem', verbose_name='Гео')), ],
], options={
options={ 'verbose_name': 'Гео',
'verbose_name': 'Гео', 'verbose_name_plural': 'Гео',
'verbose_name_plural': 'Гео', 'ordering': ['-timestamp'],
'constraints': [models.UniqueConstraint(fields=('timestamp', 'coords'), name='unique_geo_combination')], },
}, ),
), migrations.CreateModel(
migrations.AddIndex( name='ObjItem',
model_name='parameter', fields=[
index=models.Index(fields=['id_satellite', 'frequency'], name='mainapp_par_id_sate_cbfab2_idx'), ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
), ('name', models.CharField(blank=True, db_index=True, help_text='Название объекта/источника сигнала', max_length=100, null=True, verbose_name='Имя объекта')),
migrations.AddIndex( ('created_at', models.DateTimeField(auto_now_add=True, help_text='Дата и время создания записи', verbose_name='Дата создания')),
model_name='parameter', ('updated_at', models.DateTimeField(auto_now=True, help_text='Дата и время последнего изменения', verbose_name='Дата последнего изменения')),
index=models.Index(fields=['frequency', 'polarization'], name='mainapp_par_frequen_75a049_idx'), ('created_by', models.ForeignKey(blank=True, help_text='Пользователь, создавший запись', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='objitems_created', to='mainapp.customuser', verbose_name='Создан пользователем')),
), ('lyngsat_source', models.ForeignKey(blank=True, help_text='Связанный источник из базы LyngSat (ТВ)', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='objitems', to='lyngsatapp.lyngsat', verbose_name='Источник LyngSat')),
] ],
options={
'verbose_name': 'Объект',
'verbose_name_plural': 'Объекты',
'ordering': ['-updated_at'],
},
),
]

View File

@@ -0,0 +1,150 @@
# Generated by Django 5.2.7 on 2025-11-12 14:21
import django.db.models.deletion
import mainapp.models
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
('mainapp', '0001_initial'),
('mapsapp', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='objitem',
name='transponder',
field=models.ForeignKey(blank=True, help_text='Транспондер, с помощью которого была получена точка', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='transponder', to='mapsapp.transponders', verbose_name='Транспондер'),
),
migrations.AddField(
model_name='objitem',
name='updated_by',
field=models.ForeignKey(blank=True, help_text='Пользователь, последним изменивший запись', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='objitems_updated', to='mainapp.customuser', verbose_name='Изменен пользователем'),
),
migrations.AddField(
model_name='geo',
name='objitem',
field=models.OneToOneField(help_text='Связанный объект', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='geo_obj', to='mainapp.objitem', verbose_name='Объект'),
),
migrations.AddField(
model_name='parameter',
name='modulation',
field=models.ForeignKey(blank=True, default=mainapp.models.get_default_modulation, null=True, on_delete=django.db.models.deletion.SET_DEFAULT, related_name='modulations', to='mainapp.modulation', verbose_name='Модуляция'),
),
migrations.AddField(
model_name='parameter',
name='objitem',
field=models.OneToOneField(blank=True, help_text='Связанный объект', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='parameter_obj', to='mainapp.objitem', verbose_name='Объект'),
),
migrations.AddField(
model_name='parameter',
name='polarization',
field=models.ForeignKey(blank=True, default=mainapp.models.get_default_polarization, null=True, on_delete=django.db.models.deletion.SET_DEFAULT, related_name='polarizations', to='mainapp.polarization', verbose_name='Поляризация'),
),
migrations.AddField(
model_name='satellite',
name='band',
field=models.ManyToManyField(blank=True, help_text='Диапазоны работы спутника', related_name='bands', to='mainapp.band', verbose_name='Диапазоны'),
),
migrations.AddField(
model_name='satellite',
name='created_by',
field=models.ForeignKey(blank=True, help_text='Пользователь, создавший запись', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='satellite_created', to='mainapp.customuser', verbose_name='Создан пользователем'),
),
migrations.AddField(
model_name='satellite',
name='updated_by',
field=models.ForeignKey(blank=True, help_text='Пользователь, последним изменивший запись', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='satellite_updated', to='mainapp.customuser', verbose_name='Изменен пользователем'),
),
migrations.AddField(
model_name='parameter',
name='id_satellite',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='parameters', to='mainapp.satellite', verbose_name='Спутник'),
),
migrations.AddField(
model_name='sigmaparameter',
name='id_satellite',
field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='sigmapar_sat', to='mainapp.satellite', verbose_name='Спутник'),
),
migrations.AddField(
model_name='sigmaparameter',
name='modulation',
field=models.ForeignKey(blank=True, default=mainapp.models.get_default_modulation, null=True, on_delete=django.db.models.deletion.SET_DEFAULT, related_name='modulations_sigma', to='mainapp.modulation', verbose_name='Модуляция'),
),
migrations.AddField(
model_name='sigmaparameter',
name='parameter',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='sigma_parameter', to='mainapp.parameter', verbose_name='ВЧ'),
),
migrations.AddField(
model_name='sigmaparameter',
name='polarization',
field=models.ForeignKey(blank=True, default=mainapp.models.get_default_polarization, null=True, on_delete=django.db.models.deletion.SET_DEFAULT, related_name='polarizations_sigma', to='mainapp.polarization', verbose_name='Поляризация'),
),
migrations.AddField(
model_name='sigmaparameter',
name='mark',
field=models.ManyToManyField(blank=True, to='mainapp.sigmaparmark', verbose_name='Отметка'),
),
migrations.AddField(
model_name='source',
name='created_by',
field=models.ForeignKey(blank=True, help_text='Пользователь, создавший запись', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='source_created', to='mainapp.customuser', verbose_name='Создан пользователем'),
),
migrations.AddField(
model_name='source',
name='updated_by',
field=models.ForeignKey(blank=True, help_text='Пользователь, последним изменивший запись', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='source_updated', to='mainapp.customuser', verbose_name='Изменен пользователем'),
),
migrations.AddField(
model_name='objitem',
name='source',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='source', to='mainapp.source', verbose_name='ИРИ'),
),
migrations.AddField(
model_name='sigmaparameter',
name='standard',
field=models.ForeignKey(blank=True, default=mainapp.models.get_default_standard, null=True, on_delete=django.db.models.deletion.SET_DEFAULT, related_name='standards_sigma', to='mainapp.standard', verbose_name='Стандарт'),
),
migrations.AddField(
model_name='parameter',
name='standard',
field=models.ForeignKey(blank=True, default=mainapp.models.get_default_standard, null=True, on_delete=django.db.models.deletion.SET_DEFAULT, related_name='standards', to='mainapp.standard', verbose_name='Стандарт'),
),
migrations.AddIndex(
model_name='geo',
index=models.Index(fields=['-timestamp'], name='mainapp_geo_timesta_58a605_idx'),
),
migrations.AddIndex(
model_name='geo',
index=models.Index(fields=['location'], name='mainapp_geo_locatio_b855c9_idx'),
),
migrations.AddConstraint(
model_name='geo',
constraint=models.UniqueConstraint(fields=('timestamp', 'coords'), name='unique_geo_combination'),
),
migrations.AddIndex(
model_name='objitem',
index=models.Index(fields=['name'], name='mainapp_obj_name_e4f1e1_idx'),
),
migrations.AddIndex(
model_name='objitem',
index=models.Index(fields=['-updated_at'], name='mainapp_obj_updated_f46b0e_idx'),
),
migrations.AddIndex(
model_name='objitem',
index=models.Index(fields=['-created_at'], name='mainapp_obj_created_cba553_idx'),
),
migrations.AddIndex(
model_name='parameter',
index=models.Index(fields=['id_satellite', 'frequency'], name='mainapp_par_id_sate_cbfab2_idx'),
),
migrations.AddIndex(
model_name='parameter',
index=models.Index(fields=['frequency', 'polarization'], name='mainapp_par_frequen_75a049_idx'),
),
]

View File

@@ -1,35 +0,0 @@
# Generated by Django 5.2.7 on 2025-10-31 13:56
import django.db.models.deletion
import django.utils.timezone
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('mainapp', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='objitem',
name='created_at',
field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='Дата создания'),
),
migrations.AddField(
model_name='objitem',
name='created_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='objitems_created', to='mainapp.customuser', verbose_name='Создан пользователем'),
),
migrations.AddField(
model_name='objitem',
name='updated_at',
field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='Дата последнего изменения'),
),
migrations.AddField(
model_name='objitem',
name='updated_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='objitems_updated', to='mainapp.customuser', verbose_name='Изменен пользователем'),
),
]

View File

@@ -1,23 +0,0 @@
# Generated by Django 5.2.7 on 2025-10-31 14:02
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('mainapp', '0002_objitem_created_at_objitem_created_by_and_more'),
]
operations = [
migrations.AlterField(
model_name='objitem',
name='created_at',
field=models.DateTimeField(auto_now_add=True, verbose_name='Дата создания'),
),
migrations.AlterField(
model_name='objitem',
name='updated_at',
field=models.DateTimeField(auto_now=True, verbose_name='Дата последнего изменения'),
),
]

View File

@@ -1,25 +0,0 @@
# Generated by Django 5.2.7 on 2025-11-01 07:38
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('mainapp', '0003_alter_objitem_created_at_alter_objitem_updated_at'),
]
operations = [
migrations.RemoveField(
model_name='geo',
name='id_user_add',
),
migrations.RemoveField(
model_name='objitem',
name='id_user_add',
),
migrations.RemoveField(
model_name='parameter',
name='id_user_add',
),
]

View File

@@ -1,19 +0,0 @@
# Generated by Django 5.2.7 on 2025-11-07 19:35
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('mainapp', '0004_remove_geo_id_user_add_remove_objitem_id_user_add_and_more'),
]
operations = [
migrations.AlterField(
model_name='geo',
name='objitem',
field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='geo_obj', to='mainapp.objitem', verbose_name='Гео'),
),
]

View File

@@ -1,290 +0,0 @@
# Generated by Django 5.2.7 on 2025-11-07 20:58
import django.contrib.gis.db.models.fields
import django.contrib.gis.db.models.functions
import django.core.validators
import django.db.models.deletion
import django.db.models.expressions
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('mainapp', '0005_alter_geo_objitem'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.AlterModelOptions(
name='customuser',
options={'ordering': ['user__username'], 'verbose_name': 'Пользователь', 'verbose_name_plural': 'Пользователи'},
),
migrations.AlterModelOptions(
name='geo',
options={'ordering': ['-timestamp'], 'verbose_name': 'Гео', 'verbose_name_plural': 'Гео'},
),
migrations.AlterModelOptions(
name='mirror',
options={'ordering': ['name'], 'verbose_name': 'Зеркало', 'verbose_name_plural': 'Зеркала'},
),
migrations.AlterModelOptions(
name='modulation',
options={'ordering': ['name'], 'verbose_name': 'Модуляция', 'verbose_name_plural': 'Модуляции'},
),
migrations.AlterModelOptions(
name='objitem',
options={'ordering': ['-updated_at'], 'verbose_name': 'Объект', 'verbose_name_plural': 'Объекты'},
),
migrations.AlterModelOptions(
name='polarization',
options={'ordering': ['name'], 'verbose_name': 'Поляризация', 'verbose_name_plural': 'Поляризация'},
),
migrations.AlterModelOptions(
name='satellite',
options={'ordering': ['name'], 'verbose_name': 'Спутник', 'verbose_name_plural': 'Спутники'},
),
migrations.AlterModelOptions(
name='sigmaparmark',
options={'ordering': ['-timestamp'], 'verbose_name': 'Отметка', 'verbose_name_plural': 'Отметки'},
),
migrations.AlterModelOptions(
name='sourcetype',
options={'ordering': ['name'], 'verbose_name': 'Тип источника', 'verbose_name_plural': 'Типы источников'},
),
migrations.AlterModelOptions(
name='standard',
options={'ordering': ['name'], 'verbose_name': 'Стандарт', 'verbose_name_plural': 'Стандарты'},
),
migrations.AlterField(
model_name='customuser',
name='role',
field=models.CharField(choices=[('admin', 'Администратор'), ('moderator', 'Модератор'), ('user', 'Пользователь')], db_index=True, default='user', help_text='Роль пользователя в системе', max_length=20, verbose_name='Роль пользователя'),
),
migrations.AlterField(
model_name='customuser',
name='user',
field=models.OneToOneField(help_text='Связанный пользователь Django', on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='Пользователь'),
),
migrations.AlterField(
model_name='geo',
name='comment',
field=models.CharField(blank=True, help_text='Дополнительные комментарии', max_length=255, verbose_name='Комментарий'),
),
migrations.AlterField(
model_name='geo',
name='coords',
field=django.contrib.gis.db.models.fields.PointField(blank=True, help_text='Основные координаты геолокации (WGS84)', null=True, srid=4326, verbose_name='Координата геолокации'),
),
migrations.AlterField(
model_name='geo',
name='coords_kupsat',
field=django.contrib.gis.db.models.fields.PointField(blank=True, help_text='Координаты, полученные от кубсата (WGS84)', null=True, srid=4326, verbose_name='Координаты Кубсата'),
),
migrations.AlterField(
model_name='geo',
name='coords_valid',
field=django.contrib.gis.db.models.fields.PointField(blank=True, help_text='Координаты, предоставленные оперативным отделом (WGS84)', null=True, srid=4326, verbose_name='Координаты оперативников'),
),
migrations.AlterField(
model_name='geo',
name='distance_coords_kup',
field=models.GeneratedField(db_persist=True, expression=django.db.models.expressions.CombinedExpression(django.contrib.gis.db.models.functions.Distance('coords', 'coords_kupsat'), '/', models.Value(1000)), null=True, output_field=models.FloatField(), verbose_name='Расстояние между кубсатом и гео, км'),
),
migrations.AlterField(
model_name='geo',
name='distance_kup_valid',
field=models.GeneratedField(db_persist=True, expression=django.db.models.expressions.CombinedExpression(django.contrib.gis.db.models.functions.Distance('coords_valid', 'coords_kupsat'), '/', models.Value(1000)), null=True, output_field=models.FloatField(), verbose_name='Расстояние между кубсатом и оперативным отделом, км'),
),
migrations.AlterField(
model_name='geo',
name='is_average',
field=models.BooleanField(blank=True, help_text='Является ли координата усредненной', null=True, verbose_name='Усреднённое'),
),
migrations.AlterField(
model_name='geo',
name='location',
field=models.CharField(blank=True, help_text='Текстовое описание местоположения', max_length=255, null=True, verbose_name='Местоположение'),
),
migrations.AlterField(
model_name='geo',
name='mirrors',
field=models.ManyToManyField(blank=True, help_text='Зеркала антенн, использованные для приема', related_name='geo_mirrors', to='mainapp.mirror', verbose_name='Зеркала'),
),
migrations.AlterField(
model_name='geo',
name='objitem',
field=models.OneToOneField(help_text='Связанный объект', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='geo_obj', to='mainapp.objitem', verbose_name='Объект'),
),
migrations.AlterField(
model_name='geo',
name='timestamp',
field=models.DateTimeField(blank=True, db_index=True, help_text='Время фиксации геолокации', null=True, verbose_name='Время'),
),
migrations.AlterField(
model_name='mirror',
name='name',
field=models.CharField(db_index=True, help_text='Уникальное название зеркала антенны', max_length=30, unique=True, verbose_name='Имя зеркала'),
),
migrations.AlterField(
model_name='modulation',
name='name',
field=models.CharField(db_index=True, help_text='Тип модуляции сигнала (QPSK, 8PSK, 16APSK и т.д.)', max_length=20, unique=True, verbose_name='Модуляция'),
),
migrations.AlterField(
model_name='objitem',
name='created_at',
field=models.DateTimeField(auto_now_add=True, help_text='Дата и время создания записи', verbose_name='Дата создания'),
),
migrations.AlterField(
model_name='objitem',
name='created_by',
field=models.ForeignKey(blank=True, help_text='Пользователь, создавший запись', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='objitems_created', to='mainapp.customuser', verbose_name='Создан пользователем'),
),
migrations.AlterField(
model_name='objitem',
name='name',
field=models.CharField(blank=True, db_index=True, help_text='Название объекта/источника сигнала', max_length=100, null=True, verbose_name='Имя объекта'),
),
migrations.AlterField(
model_name='objitem',
name='updated_at',
field=models.DateTimeField(auto_now=True, help_text='Дата и время последнего изменения', verbose_name='Дата последнего изменения'),
),
migrations.AlterField(
model_name='objitem',
name='updated_by',
field=models.ForeignKey(blank=True, help_text='Пользователь, последним изменивший запись', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='objitems_updated', to='mainapp.customuser', verbose_name='Изменен пользователем'),
),
migrations.AlterField(
model_name='parameter',
name='bod_velocity',
field=models.FloatField(blank=True, default=0, help_text='Символьная скорость должна быть положительной', null=True, validators=[django.core.validators.MinValueValidator(0)], verbose_name='Символьная скорость, БОД'),
),
migrations.AlterField(
model_name='parameter',
name='freq_range',
field=models.FloatField(blank=True, default=0, help_text='Полоса частот в диапазоне от 0 до 1000 МГц', null=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000)], verbose_name='Полоса частот, МГц'),
),
migrations.AlterField(
model_name='parameter',
name='frequency',
field=models.FloatField(blank=True, db_index=True, default=0, help_text='Частота в диапазоне от 0 до 50000 МГц', null=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(50000)], verbose_name='Частота, МГц'),
),
migrations.AlterField(
model_name='parameter',
name='snr',
field=models.FloatField(blank=True, default=0, help_text='Отношение сигнал/шум в диапазоне от -50 до 100 дБ', null=True, validators=[django.core.validators.MinValueValidator(-50), django.core.validators.MaxValueValidator(100)], verbose_name='ОСШ'),
),
migrations.AlterField(
model_name='polarization',
name='name',
field=models.CharField(db_index=True, help_text='Тип поляризации (H - горизонтальная, V - вертикальная, L - левая круговая, R - правая круговая)', max_length=20, unique=True, verbose_name='Поляризация'),
),
migrations.AlterField(
model_name='satellite',
name='name',
field=models.CharField(db_index=True, help_text='Название спутника', max_length=100, unique=True, verbose_name='Имя спутника'),
),
migrations.AlterField(
model_name='satellite',
name='norad',
field=models.IntegerField(blank=True, help_text='Идентификатор NORAD для отслеживания спутника', null=True, verbose_name='NORAD ID'),
),
migrations.AlterField(
model_name='sigmaparameter',
name='bod_velocity',
field=models.FloatField(blank=True, default=0, help_text='Символьная скорость должна быть положительной', null=True, validators=[django.core.validators.MinValueValidator(0)], verbose_name='Символьная скорость, БОД'),
),
migrations.AlterField(
model_name='sigmaparameter',
name='datetime_begin',
field=models.DateTimeField(blank=True, help_text='Дата и время начала измерения', null=True, verbose_name='Время начала измерения'),
),
migrations.AlterField(
model_name='sigmaparameter',
name='datetime_end',
field=models.DateTimeField(blank=True, help_text='Дата и время окончания измерения', null=True, verbose_name='Время окончания измерения'),
),
migrations.AlterField(
model_name='sigmaparameter',
name='freq_range',
field=models.FloatField(blank=True, default=0, help_text='Полоса частот в диапазоне от 0 до 1000 МГц', null=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000)], verbose_name='Полоса частот, МГц'),
),
migrations.AlterField(
model_name='sigmaparameter',
name='frequency',
field=models.FloatField(blank=True, db_index=True, default=0, help_text='Частота в диапазоне от 0 до 50000 МГц', null=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(50000)], verbose_name='Частота, МГц'),
),
migrations.AlterField(
model_name='sigmaparameter',
name='packets',
field=models.BooleanField(blank=True, help_text='Наличие пакетной передачи', null=True, verbose_name='Пакетность'),
),
migrations.AlterField(
model_name='sigmaparameter',
name='power',
field=models.FloatField(blank=True, default=0, help_text='Мощность сигнала в диапазоне от -100 до 100 дБм', null=True, validators=[django.core.validators.MinValueValidator(-100), django.core.validators.MaxValueValidator(100)], verbose_name='Мощность, дБм'),
),
migrations.AlterField(
model_name='sigmaparameter',
name='snr',
field=models.FloatField(blank=True, default=0, help_text='Отношение сигнал/шум в диапазоне от -50 до 100 дБ', null=True, validators=[django.core.validators.MinValueValidator(-50), django.core.validators.MaxValueValidator(100)], verbose_name='ОСШ, Дб'),
),
migrations.AlterField(
model_name='sigmaparameter',
name='status',
field=models.CharField(blank=True, help_text='Статус измерения', max_length=20, null=True, verbose_name='Статус'),
),
migrations.AlterField(
model_name='sigmaparameter',
name='transfer',
field=models.FloatField(choices=[(-1.0, '-'), (9750.0, '9750 МГц'), (10750.0, '10750 МГц')], default=-1.0, help_text='Выберите перенос по частоте', verbose_name='Перенос по частоте'),
),
migrations.AlterField(
model_name='sigmaparmark',
name='mark',
field=models.BooleanField(blank=True, help_text='True - сигнал обнаружен, False - сигнал отсутствует', null=True, verbose_name='Наличие сигнала'),
),
migrations.AlterField(
model_name='sigmaparmark',
name='timestamp',
field=models.DateTimeField(blank=True, db_index=True, help_text='Время фиксации отметки', null=True, verbose_name='Время'),
),
migrations.AlterField(
model_name='sourcetype',
name='name',
field=models.CharField(db_index=True, help_text='Тип источника сигнала', max_length=50, unique=True, verbose_name='Тип источника'),
),
migrations.AlterField(
model_name='sourcetype',
name='objitem',
field=models.OneToOneField(help_text='Связанный объект', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='source_type_obj', to='mainapp.objitem', verbose_name='Объект'),
),
migrations.AlterField(
model_name='standard',
name='name',
field=models.CharField(db_index=True, help_text='Стандарт передачи данных (DVB-S, DVB-S2, DVB-S2X и т.д.)', max_length=20, unique=True, verbose_name='Стандарт'),
),
migrations.AddIndex(
model_name='geo',
index=models.Index(fields=['-timestamp'], name='mainapp_geo_timesta_58a605_idx'),
),
migrations.AddIndex(
model_name='geo',
index=models.Index(fields=['location'], name='mainapp_geo_locatio_b855c9_idx'),
),
migrations.AddIndex(
model_name='objitem',
index=models.Index(fields=['name'], name='mainapp_obj_name_e4f1e1_idx'),
),
migrations.AddIndex(
model_name='objitem',
index=models.Index(fields=['-updated_at'], name='mainapp_obj_updated_f46b0e_idx'),
),
migrations.AddIndex(
model_name='objitem',
index=models.Index(fields=['-created_at'], name='mainapp_obj_created_cba553_idx'),
),
]

View File

@@ -1,23 +0,0 @@
# Generated by Django 5.2.7 on 2025-11-10 18:39
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('mainapp', '0006_alter_customuser_options_alter_geo_options_and_more'),
]
operations = [
migrations.RemoveField(
model_name='parameter',
name='objitems',
),
migrations.AddField(
model_name='parameter',
name='objitem',
field=models.OneToOneField(blank=True, help_text='Связанный объект', null=True, on_delete=django.db.models.deletion.CASCADE, related_name='parameter_obj', to='mainapp.objitem', verbose_name='Объект'),
),
]

View File

@@ -1,63 +0,0 @@
# Generated by Django 5.2.7 on 2025-11-11 13:59
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('mainapp', '0007_remove_parameter_objitems_parameter_objitem'),
]
operations = [
migrations.RemoveField(
model_name='sourcetype',
name='objitem',
),
migrations.AddField(
model_name='objitem',
name='source_type_id',
field=models.ForeignKey(blank=True, help_text='Тип источника сигнала', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='objitems_sourcetype', to='mainapp.sourcetype', verbose_name='Тип источника'),
),
migrations.AlterField(
model_name='parameter',
name='bod_velocity',
field=models.FloatField(blank=True, default=0, help_text='Символьная скорость должна быть положительной', null=True, verbose_name='Символьная скорость, БОД'),
),
migrations.AlterField(
model_name='parameter',
name='freq_range',
field=models.FloatField(blank=True, default=0, help_text='Полоса частот сигнала', null=True, verbose_name='Полоса частот, МГц'),
),
migrations.AlterField(
model_name='parameter',
name='frequency',
field=models.FloatField(blank=True, db_index=True, default=0, help_text='Центральная частота сигнала', null=True, verbose_name='Частота, МГц'),
),
migrations.AlterField(
model_name='parameter',
name='snr',
field=models.FloatField(blank=True, default=0, help_text='Отношение сигнал/шум', null=True, verbose_name='ОСШ'),
),
migrations.AlterField(
model_name='sigmaparameter',
name='bod_velocity',
field=models.FloatField(blank=True, default=0, help_text='Символьная скорость должна быть положительной', null=True, verbose_name='Символьная скорость, БОД'),
),
migrations.AlterField(
model_name='sigmaparameter',
name='freq_range',
field=models.FloatField(blank=True, default=0, help_text='Полоса частот', null=True, verbose_name='Полоса частот, МГц'),
),
migrations.AlterField(
model_name='sigmaparameter',
name='frequency',
field=models.FloatField(blank=True, db_index=True, default=0, help_text='Центральная частота сигнала', null=True, verbose_name='Частота, МГц'),
),
migrations.AlterField(
model_name='sigmaparameter',
name='power',
field=models.FloatField(blank=True, default=0, help_text='Мощность сигнала', null=True, verbose_name='Мощность, дБм'),
),
]

View File

@@ -1,27 +0,0 @@
# Generated by Django 5.2.7 on 2025-11-11 19:02
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('lyngsatapp', '0002_alter_lyngsat_last_update'),
('mainapp', '0008_remove_sourcetype_objitem_objitem_source_type_id_and_more'),
]
operations = [
migrations.RemoveField(
model_name='objitem',
name='source_type_id',
),
migrations.AddField(
model_name='objitem',
name='lyngsat_source',
field=models.ForeignKey(blank=True, help_text='Связанный источник из базы LyngSat (ТВ)', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='objitems', to='lyngsatapp.lyngsat', verbose_name='Источник LyngSat'),
),
migrations.DeleteModel(
name='SourceType',
),
]

View File

@@ -201,6 +201,32 @@ class Standard(models.Model):
verbose_name_plural = "Стандарты" verbose_name_plural = "Стандарты"
ordering = ["name"] ordering = ["name"]
class Band(models.Model):
name = models.CharField(
max_length=50,
unique=True,
verbose_name="Название",
help_text="Название диапазона",
)
border_start = models.FloatField(
blank=True,
null=True,
verbose_name="Нижняя граница диапазона, МГц"
)
border_end = models.FloatField(
blank=True,
null=True,
verbose_name="Верхняя граница диапазона, МГц"
)
def __str__(self):
return self.name
class Meta:
verbose_name = "Диапазон"
verbose_name_plural = "Диапазоны"
ordering = ["name"]
class Satellite(models.Model): class Satellite(models.Model):
""" """
@@ -223,6 +249,66 @@ class Satellite(models.Model):
verbose_name="NORAD ID", verbose_name="NORAD ID",
help_text="Идентификатор NORAD для отслеживания спутника", help_text="Идентификатор NORAD для отслеживания спутника",
) )
band = models.ManyToManyField(
Band,
related_name="bands",
verbose_name="Диапазоны",
blank=True,
help_text="Диапазоны работы спутника",
)
undersat_point = models.FloatField(
blank=True,
null=True,
verbose_name="Подспутниковая точка, градусы",
help_text="Подспутниковая точка в градусах. Восточное полушарие с +, западное с -",
)
url = models.URLField(
blank=True,
null=True,
verbose_name="Ссылка на источник",
help_text="Ссылка на сайт, где можно проверить информацию",
)
comment = models.TextField(
blank=True,
null=True,
verbose_name="Комментарий",
help_text="Любой возможный комменатрий",
)
launch_date = models.DateField(
blank=True,
null=True,
verbose_name="Дата запуска",
help_text="Дата запуска спутника",
)
created_at = models.DateTimeField(
auto_now_add=True,
verbose_name="Дата создания",
help_text="Дата и время создания записи",
)
created_by = models.ForeignKey(
CustomUser,
on_delete=models.SET_NULL,
related_name="satellite_created",
null=True,
blank=True,
verbose_name="Создан пользователем",
help_text="Пользователь, создавший запись",
)
updated_at = models.DateTimeField(
auto_now=True,
verbose_name="Дата последнего изменения",
help_text="Дата и время последнего изменения",
)
updated_by = models.ForeignKey(
CustomUser,
on_delete=models.SET_NULL,
related_name="satellite_updated",
null=True,
blank=True,
verbose_name="Изменен пользователем",
help_text="Пользователь, последним изменивший запись",
)
def __str__(self): def __str__(self):
return self.name return self.name
@@ -283,11 +369,73 @@ class ObjItemManager(models.Manager):
return self.get_queryset().by_user(user) return self.get_queryset().by_user(user)
class Source(models.Model):
"""
Модель источника сигнала.
"""
coords_kupsat = gis.PointField(
srid=4326,
null=True,
blank=True,
verbose_name="Координаты Кубсата",
help_text="Координаты, полученные от кубсата (WGS84)",
)
coords_valid = gis.PointField(
srid=4326,
null=True,
blank=True,
verbose_name="Координаты оперативников",
help_text="Координаты, предоставленные оперативным отделом (WGS84)",
)
coords_reference = gis.PointField(
srid=4326,
null=True,
blank=True,
verbose_name="Координаты справочные",
help_text="Координаты, ещё кем-то проверенные (WGS84)",
)
created_at = models.DateTimeField(
auto_now_add=True,
verbose_name="Дата создания",
help_text="Дата и время создания записи",
)
created_by = models.ForeignKey(
CustomUser,
on_delete=models.SET_NULL,
related_name="source_created",
null=True,
blank=True,
verbose_name="Создан пользователем",
help_text="Пользователь, создавший запись",
)
updated_at = models.DateTimeField(
auto_now=True,
verbose_name="Дата последнего изменения",
help_text="Дата и время последнего изменения",
)
updated_by = models.ForeignKey(
CustomUser,
on_delete=models.SET_NULL,
related_name="source_updated",
null=True,
blank=True,
verbose_name="Изменен пользователем",
help_text="Пользователь, последним изменивший запись",
)
class Meta:
verbose_name = "Источник"
verbose_name_plural = "Источники"
class ObjItem(models.Model): class ObjItem(models.Model):
""" """
Модель объекта (источника сигнала). Модель точки ГЛ.
Центральная модель, объединяющая информацию о ВЧ параметрах, геолокации и типе источника. Центральная модель, объединяющая информацию о ВЧ параметрах, геолокации.
""" """
# Основные поля # Основные поля
@@ -299,6 +447,22 @@ class ObjItem(models.Model):
db_index=True, db_index=True,
help_text="Название объекта/источника сигнала", help_text="Название объекта/источника сигнала",
) )
source = models.ForeignKey(
Source,
on_delete=models.CASCADE,
null=True,
verbose_name="ИРИ",
related_name="source",
)
transponder = models.ForeignKey(
"mapsapp.Transponders",
on_delete=models.SET_NULL,
related_name="transponder",
null=True,
blank=True,
verbose_name="Транспондер",
help_text="Транспондер, с помощью которого была получена точка",
)
# Метаданные # Метаданные
created_at = models.DateTimeField( created_at = models.DateTimeField(
@@ -679,46 +843,32 @@ class Geo(models.Model):
verbose_name="Координата геолокации", verbose_name="Координата геолокации",
help_text="Основные координаты геолокации (WGS84)", help_text="Основные координаты геолокации (WGS84)",
) )
coords_kupsat = gis.PointField(
srid=4326,
null=True,
blank=True,
verbose_name="Координаты Кубсата",
help_text="Координаты, полученные от кубсата (WGS84)",
)
coords_valid = gis.PointField(
srid=4326,
null=True,
blank=True,
verbose_name="Координаты оперативников",
help_text="Координаты, предоставленные оперативным отделом (WGS84)",
)
# Вычисляемые поля - расстояния # Вычисляемые поля - расстояния
distance_coords_kup = models.GeneratedField( # distance_coords_kup = models.GeneratedField(
expression=functions.Distance("coords", "coords_kupsat") / 1000, # expression=functions.Distance("coords", "coords_kupsat") / 1000,
output_field=models.FloatField(), # output_field=models.FloatField(),
db_persist=True, # db_persist=True,
null=True, # null=True,
blank=True, # blank=True,
verbose_name="Расстояние между кубсатом и гео, км", # verbose_name="Расстояние между кубсатом и гео, км",
) # )
distance_coords_valid = models.GeneratedField( # distance_coords_valid = models.GeneratedField(
expression=functions.Distance("coords", "coords_valid") / 1000, # expression=functions.Distance("coords", "coords_valid") / 1000,
output_field=models.FloatField(), # output_field=models.FloatField(),
db_persist=True, # db_persist=True,
null=True, # null=True,
blank=True, # blank=True,
verbose_name="Расстояние между гео и оперативным отделом, км", # verbose_name="Расстояние между гео и оперативным отделом, км",
) # )
distance_kup_valid = models.GeneratedField( # distance_kup_valid = models.GeneratedField(
expression=functions.Distance("coords_valid", "coords_kupsat") / 1000, # expression=functions.Distance("coords_valid", "coords_kupsat") / 1000,
output_field=models.FloatField(), # output_field=models.FloatField(),
db_persist=True, # db_persist=True,
null=True, # null=True,
blank=True, # blank=True,
verbose_name="Расстояние между кубсатом и оперативным отделом, км", # verbose_name="Расстояние между кубсатом и оперативным отделом, км",
) # )
# Связи # Связи
mirrors = models.ManyToManyField( mirrors = models.ManyToManyField(

View File

@@ -95,8 +95,8 @@
</div> </div>
<h3 class="card-title mb-0">Добавление транспондеров</h3> <h3 class="card-title mb-0">Добавление транспондеров</h3>
</div> </div>
<p class="card-text">Добавьте список транспондеров из JSON-файла в базу данных. Требуется наличие файла transponders.json.</p> <p class="card-text">Добавьте список транспондеров в базу данных.</p>
<a href="{% url 'mainapp:add_trans' %}" class="btn btn-warning disabled"> <a href="{% url 'mainapp:add_trans' %}" class="btn btn-warning">
Добавить транспондеры Добавить транспондеры
</a> </a>
</div> </div>

View File

@@ -1,37 +1,44 @@
# Generated by Django 5.2.7 on 2025-10-31 13:36 # Generated by Django 5.2.7 on 2025-11-12 14:21
import django.db.models.deletion import django.db.models.deletion
import django.db.models.expressions import django.db.models.expressions
import django.db.models.functions.math import django.db.models.functions.math
import mainapp.models import mainapp.models
from django.db import migrations, models from django.db import migrations, models
class Migration(migrations.Migration): class Migration(migrations.Migration):
initial = True initial = True
dependencies = [ dependencies = [
('mainapp', '0001_initial'), ('mainapp', '0001_initial'),
] ]
operations = [ operations = [
migrations.CreateModel( migrations.CreateModel(
name='Transponders', name='Transponders',
fields=[ fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(blank=True, max_length=30, null=True, verbose_name='Название транспондера')), ('name', models.CharField(blank=True, db_index=True, help_text='Название транспондера', max_length=30, null=True, verbose_name='Название транспондера')),
('downlink', models.FloatField(blank=True, null=True, verbose_name='Downlink')), ('downlink', models.FloatField(blank=True, null=True, verbose_name='Downlink')),
('frequency_range', models.FloatField(blank=True, null=True, verbose_name='Полоса')), ('frequency_range', models.FloatField(blank=True, null=True, verbose_name='Полоса')),
('uplink', models.FloatField(blank=True, null=True, verbose_name='Uplink')), ('uplink', models.FloatField(blank=True, null=True, verbose_name='Uplink')),
('zone_name', models.CharField(blank=True, max_length=255, null=True, verbose_name='Название зоны')), ('zone_name', models.CharField(blank=True, db_index=True, help_text='Название зоны покрытия транспондера', max_length=255, null=True, verbose_name='Название зоны')),
('transfer', models.GeneratedField(db_persist=True, expression=models.ExpressionWrapper(django.db.models.functions.math.Abs(django.db.models.expressions.CombinedExpression(models.F('downlink'), '-', models.F('uplink'))), output_field=models.FloatField()), null=True, output_field=models.FloatField(), verbose_name='Перенос')), ('snr', models.FloatField(blank=True, help_text='Полоса частот в МГц (0-1000)', null=True, verbose_name='Полоса')),
('polarization', models.ForeignKey(blank=True, default=mainapp.models.get_default_polarization, null=True, on_delete=django.db.models.deletion.SET_DEFAULT, related_name='tran_polarizations', to='mainapp.polarization', verbose_name='Поляризация')), ('created_at', models.DateTimeField(auto_now_add=True, help_text='Дата и время создания записи', verbose_name='Дата создания')),
('sat_id', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='tran_satellite', to='mainapp.satellite', verbose_name='Спутник')), ('updated_at', models.DateTimeField(auto_now=True, help_text='Дата и время последнего изменения', verbose_name='Дата последнего изменения')),
], ('transfer', models.GeneratedField(db_persist=True, expression=models.ExpressionWrapper(django.db.models.functions.math.Abs(django.db.models.expressions.CombinedExpression(models.F('downlink'), '-', models.F('uplink'))), output_field=models.FloatField()), null=True, output_field=models.FloatField(), verbose_name='Перенос')),
options={ ('created_by', models.ForeignKey(blank=True, help_text='Пользователь, создавший запись', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='transponder_created', to='mainapp.customuser', verbose_name='Создан пользователем')),
'verbose_name': 'Транспондер', ('polarization', models.ForeignKey(blank=True, default=mainapp.models.get_default_polarization, help_text='Поляризация сигнала', null=True, on_delete=django.db.models.deletion.SET_DEFAULT, related_name='tran_polarizations', to='mainapp.polarization', verbose_name='Поляризация')),
'verbose_name_plural': 'Транспондеры', ('sat_id', models.ForeignKey(help_text='Спутник, которому принадлежит транспондер', on_delete=django.db.models.deletion.PROTECT, related_name='tran_satellite', to='mainapp.satellite', verbose_name='Спутник')),
}, ('updated_by', models.ForeignKey(blank=True, help_text='Пользователь, последним изменивший запись', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='transponder_updated', to='mainapp.customuser', verbose_name='Изменен пользователем')),
), ],
] options={
'verbose_name': 'Транспондер',
'verbose_name_plural': 'Транспондеры',
'ordering': ['sat_id', 'downlink'],
'indexes': [models.Index(fields=['sat_id', 'downlink'], name='mapsapp_tra_sat_id__3e3fd7_idx'), models.Index(fields=['sat_id', 'zone_name'], name='mapsapp_tra_sat_id__305ae7_idx')],
},
),
]

View File

@@ -1,64 +0,0 @@
# Generated by Django 5.2.7 on 2025-11-07 20:58
import django.core.validators
import django.db.models.deletion
import mainapp.models
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('mainapp', '0006_alter_customuser_options_alter_geo_options_and_more'),
('mapsapp', '0001_initial'),
]
operations = [
migrations.AlterModelOptions(
name='transponders',
options={'ordering': ['sat_id', 'downlink'], 'verbose_name': 'Транспондер', 'verbose_name_plural': 'Транспондеры'},
),
migrations.AlterField(
model_name='transponders',
name='downlink',
field=models.FloatField(blank=True, help_text='Частота downlink в МГц (0-50000)', null=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(50000)], verbose_name='Downlink'),
),
migrations.AlterField(
model_name='transponders',
name='frequency_range',
field=models.FloatField(blank=True, help_text='Полоса частот в МГц (0-1000)', null=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(1000)], verbose_name='Полоса'),
),
migrations.AlterField(
model_name='transponders',
name='name',
field=models.CharField(blank=True, db_index=True, help_text='Название транспондера', max_length=30, null=True, verbose_name='Название транспондера'),
),
migrations.AlterField(
model_name='transponders',
name='polarization',
field=models.ForeignKey(blank=True, default=mainapp.models.get_default_polarization, help_text='Поляризация сигнала', null=True, on_delete=django.db.models.deletion.SET_DEFAULT, related_name='tran_polarizations', to='mainapp.polarization', verbose_name='Поляризация'),
),
migrations.AlterField(
model_name='transponders',
name='sat_id',
field=models.ForeignKey(help_text='Спутник, которому принадлежит транспондер', on_delete=django.db.models.deletion.PROTECT, related_name='tran_satellite', to='mainapp.satellite', verbose_name='Спутник'),
),
migrations.AlterField(
model_name='transponders',
name='uplink',
field=models.FloatField(blank=True, help_text='Частота uplink в МГц (0-50000)', null=True, validators=[django.core.validators.MinValueValidator(0), django.core.validators.MaxValueValidator(50000)], verbose_name='Uplink'),
),
migrations.AlterField(
model_name='transponders',
name='zone_name',
field=models.CharField(blank=True, db_index=True, help_text='Название зоны покрытия транспондера', max_length=255, null=True, verbose_name='Название зоны'),
),
migrations.AddIndex(
model_name='transponders',
index=models.Index(fields=['sat_id', 'downlink'], name='mapsapp_tra_sat_id__3e3fd7_idx'),
),
migrations.AddIndex(
model_name='transponders',
index=models.Index(fields=['sat_id', 'zone_name'], name='mapsapp_tra_sat_id__305ae7_idx'),
),
]

View File

@@ -6,7 +6,7 @@ from django.db.models import ExpressionWrapper, F
from django.db.models.functions import Abs from django.db.models.functions import Abs
# Local imports # Local imports
from mainapp.models import Polarization, Satellite, get_default_polarization from mainapp.models import Polarization, Satellite, get_default_polarization, CustomUser
class Transponders(models.Model): class Transponders(models.Model):
@@ -29,22 +29,22 @@ class Transponders(models.Model):
blank=True, blank=True,
null=True, null=True,
verbose_name="Downlink", verbose_name="Downlink",
validators=[MinValueValidator(0), MaxValueValidator(50000)], # validators=[MinValueValidator(0), MaxValueValidator(50000)],
help_text="Частота downlink в МГц (0-50000)" # help_text="Частота downlink в МГц (0-50000)"
) )
frequency_range = models.FloatField( frequency_range = models.FloatField(
blank=True, blank=True,
null=True, null=True,
verbose_name="Полоса", verbose_name="Полоса",
validators=[MinValueValidator(0), MaxValueValidator(1000)], # validators=[MinValueValidator(0), MaxValueValidator(1000)],
help_text="Полоса частот в МГц (0-1000)" # help_text="Полоса частот в МГц (0-1000)"
) )
uplink = models.FloatField( uplink = models.FloatField(
blank=True, blank=True,
null=True, null=True,
verbose_name="Uplink", verbose_name="Uplink",
validators=[MinValueValidator(0), MaxValueValidator(50000)], # validators=[MinValueValidator(0), MaxValueValidator(50000)],
help_text="Частота uplink в МГц (0-50000)" # help_text="Частота uplink в МГц (0-50000)"
) )
zone_name = models.CharField( zone_name = models.CharField(
max_length=255, max_length=255,
@@ -54,6 +54,41 @@ class Transponders(models.Model):
db_index=True, db_index=True,
help_text="Название зоны покрытия транспондера" help_text="Название зоны покрытия транспондера"
) )
snr = models.FloatField(
blank=True,
null=True,
verbose_name="Полоса",
# validators=[MinValueValidator(0), MaxValueValidator(1000)],
help_text="Полоса частот в МГц (0-1000)"
)
created_at = models.DateTimeField(
auto_now_add=True,
verbose_name="Дата создания",
help_text="Дата и время создания записи",
)
created_by = models.ForeignKey(
CustomUser,
on_delete=models.SET_NULL,
related_name="transponder_created",
null=True,
blank=True,
verbose_name="Создан пользователем",
help_text="Пользователь, создавший запись",
)
updated_at = models.DateTimeField(
auto_now=True,
verbose_name="Дата последнего изменения",
help_text="Дата и время последнего изменения",
)
updated_by = models.ForeignKey(
CustomUser,
on_delete=models.SET_NULL,
related_name="transponder_updated",
null=True,
blank=True,
verbose_name="Изменен пользователем",
help_text="Пользователь, последним изменивший запись",
)
# Связи # Связи
polarization = models.ForeignKey( polarization = models.ForeignKey(
@@ -88,17 +123,17 @@ class Transponders(models.Model):
verbose_name="Перенос" verbose_name="Перенос"
) )
def clean(self): # def clean(self):
"""Валидация на уровне модели""" # """Валидация на уровне модели"""
super().clean() # super().clean()
# Проверка что downlink и uplink заданы # # Проверка что downlink и uplink заданы
if self.downlink and self.uplink: # if self.downlink and self.uplink:
# Обычно uplink выше downlink для спутниковой связи # # Обычно uplink выше downlink для спутниковой связи
if self.uplink < self.downlink: # if self.uplink < self.downlink:
raise ValidationError({ # raise ValidationError({
'uplink': 'Частота uplink обычно выше частоты downlink' # 'uplink': 'Частота uplink обычно выше частоты downlink'
}) # })
def __str__(self): def __str__(self):
if self.name: if self.name:

View File

@@ -1,165 +1,169 @@
# Standard library imports # Standard library imports
import json import json
import re import re
from io import BytesIO from io import BytesIO
# Third-party imports # Third-party imports
import requests import requests
# Local imports # Local imports
from mainapp.models import Polarization, Satellite from mainapp.models import Polarization, Satellite
from .models import Transponders from .models import Transponders
def search_satellite_on_page(data: dict, satellite_name: str): def search_satellite_on_page(data: dict, satellite_name: str):
for pos, value in data.get('page', {}).get('positions').items(): for pos, value in data.get('page', {}).get('positions').items():
for name in value['satellites']: for name in value['satellites']:
if name['other_names'] is None: if name['other_names'] is None:
name['other_names'] = '' name['other_names'] = ''
if satellite_name.lower() in name['name'].lower() or satellite_name.lower() in name['other_names'].lower(): if satellite_name.lower() in name['name'].lower() or satellite_name.lower() in name['other_names'].lower():
return pos, name['id'] return pos, name['id']
return '', '' return '', ''
def get_footprint_data(position: str = 62) -> dict: def get_footprint_data(position: str = 62) -> dict:
"""Возвращает словарь с данным по footprint для спутников на выбранной долготе""" """Возвращает словарь с данным по footprint для спутников на выбранной долготе"""
response = requests.get(f"https://www.satbeams.com/footprints?position={position}") response = requests.get(f"https://www.satbeams.com/footprints?position={position}")
response.raise_for_status() response.raise_for_status()
match = re.search(r'var data = ({.*?});', response.text, re.DOTALL) match = re.search(r'var data = ({.*?});', response.text, re.DOTALL)
if match: if match:
json_str = match.group(1) json_str = match.group(1)
try: try:
data = json.loads(json_str) data = json.loads(json_str)
return data.get("page", {}).get("footprint_data", {}).get("beams",[]) return data.get("page", {}).get("footprint_data", {}).get("beams",[])
except json.JSONDecodeError as e: except json.JSONDecodeError as e:
print("Ошибка парсинга JSON:", e) print("Ошибка парсинга JSON:", e)
else: else:
print("Нужных данных не найдено") print("Нужных данных не найдено")
return {} return {}
def get_all_page_data(url:str = 'https://www.satbeams.com/footprints') -> dict: def get_all_page_data(url:str = 'https://www.satbeams.com/footprints') -> dict:
"""Возвращает словарь с данными по всем спутникам на странице""" """Возвращает словарь с данными по всем спутникам на странице"""
response = requests.get(url) response = requests.get(url)
response.raise_for_status() response.raise_for_status()
match = re.search(r'var data = ({.*?});', response.text, re.DOTALL) match = re.search(r'var data = ({.*?});', response.text, re.DOTALL)
if match: if match:
json_str = match.group(1) json_str = match.group(1)
try: try:
data = json.loads(json_str) data = json.loads(json_str)
# Файл json на диске для достоверности # Файл json на диске для достоверности
with open('data.json', 'w') as jf: with open('data.json', 'w') as jf:
json.dump(data, jf, indent=2) json.dump(data, jf, indent=2)
return data return data
except json.JSONDecodeError as e: except json.JSONDecodeError as e:
print("Ошибка парсинга JSON:", e) print("Ошибка парсинга JSON:", e)
else: else:
print("Нужных данных не найдено") print("Нужных данных не найдено")
return {} return {}
def get_names_footprints_for_satellite(footprint_data: dict, sat_id: str) -> list[str]: def get_names_footprints_for_satellite(footprint_data: dict, sat_id: str) -> list[str]:
names = [] names = []
for beam in footprint_data: for beam in footprint_data:
if 'ku' in beam['band'].lower() and sat_id in beam['satellite_id']: if 'ku' in beam['band'].lower() and sat_id in beam['satellite_id']:
names.append( names.append(
{ {
"name": beam['name'], "name": beam['name'],
"fullname": beam['fullname'][8:] "fullname": beam['fullname'][8:]
} }
) )
return names return names
def get_band_names(satellite_name: str) -> list[str]: def get_band_names(satellite_name: str) -> list[str]:
data = get_all_page_data() data = get_all_page_data()
pos, sat_id = search_satellite_on_page(data, satellite_name) pos, sat_id = search_satellite_on_page(data, satellite_name)
footprints = get_footprint_data(pos) footprints = get_footprint_data(pos)
names = get_names_footprints_for_satellite(footprints, sat_id) names = get_names_footprints_for_satellite(footprints, sat_id)
return names return names
def parse_transponders_from_json(filepath: str): def parse_transponders_from_json(filepath: str):
with open(filepath, encoding="utf-8") as jf: with open(filepath, encoding="utf-8") as jf:
data = json.load(jf) data = json.load(jf)
for sat_name, trans_zone in data["satellites"].items(): for sat_name, trans_zone in data["satellites"].items():
for zone, trans in trans_zone.items(): for zone, trans in trans_zone.items():
for tran in trans: for tran in trans:
f_b, f_e = tran["freq"][0].split("-") f_b, f_e = tran["freq"][0].split("-")
f = round((float(f_b) + float(f_e))/2, 3) f = round((float(f_b) + float(f_e))/2, 3)
f_range = round(abs(float(f_e) - float(f_b)), 3) f_range = round(abs(float(f_e) - float(f_b)), 3)
tran_obj = Transponders.objects.create( tran_obj = Transponders.objects.create(
name=tran["name"], name=tran["name"],
frequency=f, frequency=f,
frequency_range=f_range, frequency_range=f_range,
zone_name=zone, zone_name=zone,
polarization=Polarization.objects.get(name=tran["pol"]), polarization=Polarization.objects.get(name=tran["pol"]),
sat_id=Satellite.objects.get(name__iexact=sat_name) sat_id=Satellite.objects.get(name__iexact=sat_name)
) )
tran_obj.save() tran_obj.save()
# Third-party imports (additional) # Third-party imports (additional)
from lxml import etree from lxml import etree
def parse_transponders_from_xml(data_in: BytesIO): def parse_transponders_from_xml(data_in: BytesIO, user=None):
tree = etree.parse(data_in) tree = etree.parse(data_in)
ns = { ns = {
'i': 'http://www.w3.org/2001/XMLSchema-instance', 'i': 'http://www.w3.org/2001/XMLSchema-instance',
'ns': 'http://schemas.datacontract.org/2004/07/Geolocation.Domain.Utils.Repository.SatellitesSerialization.Memos', 'ns': 'http://schemas.datacontract.org/2004/07/Geolocation.Domain.Utils.Repository.SatellitesSerialization.Memos',
'tr': 'http://schemas.datacontract.org/2004/07/Geolocation.Common.Extensions' 'tr': 'http://schemas.datacontract.org/2004/07/Geolocation.Common.Extensions'
} }
satellites = tree.xpath('//ns:SatelliteMemo', namespaces=ns) satellites = tree.xpath('//ns:SatelliteMemo', namespaces=ns)
for sat in satellites[:]: for sat in satellites[:]:
name = sat.xpath('./ns:name/text()', namespaces=ns)[0] name = sat.xpath('./ns:name/text()', namespaces=ns)[0]
if name == 'X' or 'DONT USE' in name: if name == 'X' or 'DONT USE' in name:
continue continue
norad = sat.xpath('./ns:norad/text()', namespaces=ns) norad = sat.xpath('./ns:norad/text()', namespaces=ns)
beams = sat.xpath('.//ns:BeamMemo', namespaces=ns) beams = sat.xpath('.//ns:BeamMemo', namespaces=ns)
zones = {} zones = {}
for zone in beams: for zone in beams:
zone_name = zone.xpath('./ns:name/text()', namespaces=ns)[0] if zone.xpath('./ns:name/text()', namespaces=ns) else '-' zone_name = zone.xpath('./ns:name/text()', namespaces=ns)[0] if zone.xpath('./ns:name/text()', namespaces=ns) else '-'
zones[zone.xpath('./ns:id/text()', namespaces=ns)[0]] = { zones[zone.xpath('./ns:id/text()', namespaces=ns)[0]] = {
"name": zone_name, "name": zone_name,
"pol": zone.xpath('./ns:polarization/text()', namespaces=ns)[0], "pol": zone.xpath('./ns:polarization/text()', namespaces=ns)[0],
} }
transponders = sat.xpath('.//ns:TransponderMemo', namespaces=ns) transponders = sat.xpath('.//ns:TransponderMemo', namespaces=ns)
for transponder in transponders: for transponder in transponders:
tr_id = transponder.xpath('./ns:downlinkBeamId/text()', namespaces=ns)[0] tr_id = transponder.xpath('./ns:downlinkBeamId/text()', namespaces=ns)[0]
downlink_start = float(transponder.xpath('./ns:downlinkFrequency/tr:start/text()', namespaces=ns)[0]) downlink_start = float(transponder.xpath('./ns:downlinkFrequency/tr:start/text()', namespaces=ns)[0])
downlink_end = float(transponder.xpath('./ns:downlinkFrequency/tr:end/text()', namespaces=ns)[0]) downlink_end = float(transponder.xpath('./ns:downlinkFrequency/tr:end/text()', namespaces=ns)[0])
uplink_start = float(transponder.xpath('./ns:uplinkFrequency/tr:start/text()', namespaces=ns)[0]) uplink_start = float(transponder.xpath('./ns:uplinkFrequency/tr:start/text()', namespaces=ns)[0])
uplink_end = float(transponder.xpath('./ns:uplinkFrequency/tr:end/text()', namespaces=ns)[0]) uplink_end = float(transponder.xpath('./ns:uplinkFrequency/tr:end/text()', namespaces=ns)[0])
tr_data = zones[tr_id] tr_data = zones[tr_id]
# p = tr_data['pol'][0] if tr_data['pol'] else '-' # p = tr_data['pol'][0] if tr_data['pol'] else '-'
match tr_data['pol']: match tr_data['pol']:
case 'Horizontal': case 'Horizontal':
pol = 'Горизонтальная' pol = 'Горизонтальная'
case 'Vertical': case 'Vertical':
pol = 'Вертикальная' pol = 'Вертикальная'
case 'CircularRight': case 'CircularRight':
pol = 'Правая' pol = 'Правая'
case 'CircularLeft': case 'CircularLeft':
pol = 'Левая' pol = 'Левая'
case _: case _:
pol = '-' pol = '-'
tr_name = transponder.xpath('./ns:name/text()', namespaces=ns)[0] tr_name = transponder.xpath('./ns:name/text()', namespaces=ns)[0]
pol_obj, _ = Polarization.objects.get_or_create(name=pol) pol_obj, _ = Polarization.objects.get_or_create(name=pol)
sat_obj, _ = Satellite.objects.get_or_create( sat_obj, _ = Satellite.objects.get_or_create(
name=name, name=name,
defaults={ defaults={
"norad": int(norad[0]) if norad else -1 "norad": int(norad[0]) if norad else -1
}) })
trans_obj, _ = Transponders.objects.get_or_create( trans_obj, created = Transponders.objects.get_or_create(
polarization=pol_obj, polarization=pol_obj,
downlink=(downlink_start+downlink_end)/2/1000000, downlink=(downlink_start+downlink_end)/2/1000000,
uplink=(uplink_start+uplink_end)/2/1000000, uplink=(uplink_start+uplink_end)/2/1000000,
frequency_range=abs(downlink_end-downlink_start)/1000000, frequency_range=abs(downlink_end-downlink_start)/1000000,
name=tr_name, name=tr_name,
defaults={ defaults={
"zone_name": tr_data['name'], "zone_name": tr_data['name'],
"sat_id": sat_obj, "sat_id": sat_obj,
} }
) )
trans_obj.save() if user:
if created:
trans_obj.created_by = user
trans_obj.updated_by = user
trans_obj.save()

View File

@@ -0,0 +1,165 @@
# Standard library imports
import json
import re
from io import BytesIO
# Third-party imports
import requests
# Local imports
from mainapp.models import Polarization, Satellite
from .models import Transponders
def search_satellite_on_page(data: dict, satellite_name: str):
for pos, value in data.get('page', {}).get('positions').items():
for name in value['satellites']:
if name['other_names'] is None:
name['other_names'] = ''
if satellite_name.lower() in name['name'].lower() or satellite_name.lower() in name['other_names'].lower():
return pos, name['id']
return '', ''
def get_footprint_data(position: str = 62) -> dict:
"""Возвращает словарь с данным по footprint для спутников на выбранной долготе"""
response = requests.get(f"https://www.satbeams.com/footprints?position={position}")
response.raise_for_status()
match = re.search(r'var data = ({.*?});', response.text, re.DOTALL)
if match:
json_str = match.group(1)
try:
data = json.loads(json_str)
return data.get("page", {}).get("footprint_data", {}).get("beams",[])
except json.JSONDecodeError as e:
print("Ошибка парсинга JSON:", e)
else:
print("Нужных данных не найдено")
return {}
def get_all_page_data(url:str = 'https://www.satbeams.com/footprints') -> dict:
"""Возвращает словарь с данными по всем спутникам на странице"""
response = requests.get(url)
response.raise_for_status()
match = re.search(r'var data = ({.*?});', response.text, re.DOTALL)
if match:
json_str = match.group(1)
try:
data = json.loads(json_str)
# Файл json на диске для достоверности
with open('data.json', 'w') as jf:
json.dump(data, jf, indent=2)
return data
except json.JSONDecodeError as e:
print("Ошибка парсинга JSON:", e)
else:
print("Нужных данных не найдено")
return {}
def get_names_footprints_for_satellite(footprint_data: dict, sat_id: str) -> list[str]:
names = []
for beam in footprint_data:
if 'ku' in beam['band'].lower() and sat_id in beam['satellite_id']:
names.append(
{
"name": beam['name'],
"fullname": beam['fullname'][8:]
}
)
return names
def get_band_names(satellite_name: str) -> list[str]:
data = get_all_page_data()
pos, sat_id = search_satellite_on_page(data, satellite_name)
footprints = get_footprint_data(pos)
names = get_names_footprints_for_satellite(footprints, sat_id)
return names
def parse_transponders_from_json(filepath: str):
with open(filepath, encoding="utf-8") as jf:
data = json.load(jf)
for sat_name, trans_zone in data["satellites"].items():
for zone, trans in trans_zone.items():
for tran in trans:
f_b, f_e = tran["freq"][0].split("-")
f = round((float(f_b) + float(f_e))/2, 3)
f_range = round(abs(float(f_e) - float(f_b)), 3)
tran_obj = Transponders.objects.create(
name=tran["name"],
frequency=f,
frequency_range=f_range,
zone_name=zone,
polarization=Polarization.objects.get(name=tran["pol"]),
sat_id=Satellite.objects.get(name__iexact=sat_name)
)
tran_obj.save()
# Third-party imports (additional)
from lxml import etree
def parse_transponders_from_xml(data_in: BytesIO):
tree = etree.parse(data_in)
ns = {
'i': 'http://www.w3.org/2001/XMLSchema-instance',
'ns': 'http://schemas.datacontract.org/2004/07/Geolocation.Domain.Utils.Repository.SatellitesSerialization.Memos',
'tr': 'http://schemas.datacontract.org/2004/07/Geolocation.Common.Extensions'
}
satellites = tree.xpath('//ns:SatelliteMemo', namespaces=ns)
for sat in satellites[:]:
name = sat.xpath('./ns:name/text()', namespaces=ns)[0]
if name == 'X' or 'DONT USE' in name:
continue
norad = sat.xpath('./ns:norad/text()', namespaces=ns)
beams = sat.xpath('.//ns:BeamMemo', namespaces=ns)
zones = {}
for zone in beams:
zone_name = zone.xpath('./ns:name/text()', namespaces=ns)[0] if zone.xpath('./ns:name/text()', namespaces=ns) else '-'
zones[zone.xpath('./ns:id/text()', namespaces=ns)[0]] = {
"name": zone_name,
"pol": zone.xpath('./ns:polarization/text()', namespaces=ns)[0],
}
transponders = sat.xpath('.//ns:TransponderMemo', namespaces=ns)
for transponder in transponders:
tr_id = transponder.xpath('./ns:downlinkBeamId/text()', namespaces=ns)[0]
downlink_start = float(transponder.xpath('./ns:downlinkFrequency/tr:start/text()', namespaces=ns)[0])
downlink_end = float(transponder.xpath('./ns:downlinkFrequency/tr:end/text()', namespaces=ns)[0])
uplink_start = float(transponder.xpath('./ns:uplinkFrequency/tr:start/text()', namespaces=ns)[0])
uplink_end = float(transponder.xpath('./ns:uplinkFrequency/tr:end/text()', namespaces=ns)[0])
tr_data = zones[tr_id]
# p = tr_data['pol'][0] if tr_data['pol'] else '-'
match tr_data['pol']:
case 'Horizontal':
pol = 'Горизонтальная'
case 'Vertical':
pol = 'Вертикальная'
case 'CircularRight':
pol = 'Правая'
case 'CircularLeft':
pol = 'Левая'
case _:
pol = '-'
tr_name = transponder.xpath('./ns:name/text()', namespaces=ns)[0]
pol_obj, _ = Polarization.objects.get_or_create(name=pol)
sat_obj, _ = Satellite.objects.get_or_create(
name=name,
defaults={
"norad": int(norad[0]) if norad else -1
})
trans_obj, _ = Transponders.objects.get_or_create(
polarization=pol_obj,
downlink=(downlink_start+downlink_end)/2/1000000,
uplink=(uplink_start+uplink_end)/2/1000000,
frequency_range=abs(downlink_end-downlink_start)/1000000,
name=tr_name,
defaults={
"zone_name": tr_data['name'],
"sat_id": sat_obj,
}
)
trans_obj.save()