Аутентификация и кто и когда создал
This commit is contained in:
@@ -150,6 +150,11 @@ USE_I18N = True
|
|||||||
|
|
||||||
USE_TZ = True
|
USE_TZ = True
|
||||||
|
|
||||||
|
# Authentication settings
|
||||||
|
LOGIN_URL = 'login'
|
||||||
|
LOGIN_REDIRECT_URL = 'home'
|
||||||
|
LOGOUT_REDIRECT_URL = 'home'
|
||||||
|
|
||||||
|
|
||||||
# Static files (CSS, JavaScript, Images)
|
# Static files (CSS, JavaScript, Images)
|
||||||
# https://docs.djangoproject.com/en/5.2/howto/static-files/
|
# https://docs.djangoproject.com/en/5.2/howto/static-files/
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ Including another URLconf
|
|||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.urls import path, include
|
from django.urls import path, include
|
||||||
from mainapp import views
|
from mainapp import views
|
||||||
|
from django.contrib.auth import views as auth_views
|
||||||
from debug_toolbar.toolbar import debug_toolbar_urls
|
from debug_toolbar.toolbar import debug_toolbar_urls
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
@@ -24,5 +25,8 @@ urlpatterns = [
|
|||||||
path('admin/', admin.site.urls, name='admin'),
|
path('admin/', admin.site.urls, name='admin'),
|
||||||
# path('admin/map/', views.show_map_view, name='admin_show_map'),
|
# path('admin/map/', views.show_map_view, name='admin_show_map'),
|
||||||
path('', include('mainapp.urls')),
|
path('', include('mainapp.urls')),
|
||||||
path('', include('mapsapp.urls'))
|
path('', include('mapsapp.urls')),
|
||||||
|
# Authentication URLs
|
||||||
|
path('login/', auth_views.LoginView.as_view(), name='login'),
|
||||||
|
path('logout/', views.custom_logout, name='logout'),
|
||||||
] + debug_toolbar_urls()
|
] + debug_toolbar_urls()
|
||||||
|
|||||||
@@ -40,10 +40,17 @@ from .filters import GeoKupDistanceFilter, GeoValidDistanceFilter, UniqueToggleF
|
|||||||
admin.site.site_title = "Геолокация"
|
admin.site.site_title = "Геолокация"
|
||||||
admin.site.site_header = "Geolocation"
|
admin.site.site_header = "Geolocation"
|
||||||
admin.site.index_title = "Geo"
|
admin.site.index_title = "Geo"
|
||||||
|
# Unregister default User and Group since we're customizing them
|
||||||
admin.site.unregister(User)
|
admin.site.unregister(User)
|
||||||
admin.site.unregister(Group)
|
admin.site.unregister(Group)
|
||||||
|
|
||||||
|
|
||||||
|
class CustomUserInline(admin.StackedInline):
|
||||||
|
model = CustomUser
|
||||||
|
can_delete = False
|
||||||
|
verbose_name_plural = 'Дополнительная информация пользователя'
|
||||||
|
|
||||||
|
|
||||||
class LocationForm(forms.ModelForm):
|
class LocationForm(forms.ModelForm):
|
||||||
latitude_geo = forms.FloatField(required=False, label="Широта")
|
latitude_geo = forms.FloatField(required=False, label="Широта")
|
||||||
longitude_geo = forms.FloatField(required=False, label="Долгота")
|
longitude_geo = forms.FloatField(required=False, label="Долгота")
|
||||||
@@ -117,23 +124,18 @@ class GeoInline(admin.StackedInline):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class CustomUserInline(admin.StackedInline):
|
|
||||||
model = CustomUser
|
|
||||||
can_delete = False
|
|
||||||
verbose_name_plural = 'Дополнительная информация пользователя'
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(CustomUser)
|
|
||||||
class CustomUserAdmin(admin.ModelAdmin):
|
|
||||||
list_display = ('user', 'role')
|
|
||||||
list_filter = ('role',)
|
|
||||||
|
|
||||||
|
|
||||||
class UserAdmin(BaseUserAdmin):
|
class UserAdmin(BaseUserAdmin):
|
||||||
inlines = [CustomUserInline]
|
inlines = [CustomUserInline]
|
||||||
|
|
||||||
admin.site.register(User, UserAdmin)
|
admin.site.register(User, UserAdmin)
|
||||||
|
|
||||||
|
|
||||||
|
# @admin.register(CustomUser)
|
||||||
|
# class CustomUserAdmin(admin.ModelAdmin):
|
||||||
|
# list_display = ('user', 'role')
|
||||||
|
# list_filter = ('role',)
|
||||||
|
# raw_id_fields = ('user',) # For better performance with large number of users
|
||||||
|
|
||||||
@admin.register(SigmaParMark)
|
@admin.register(SigmaParMark)
|
||||||
class SigmaParMarkAdmin(admin.ModelAdmin):
|
class SigmaParMarkAdmin(admin.ModelAdmin):
|
||||||
list_display = ("mark", "timestamp")
|
list_display = ("mark", "timestamp")
|
||||||
@@ -412,7 +414,6 @@ class ParameterObjItemInline(admin.StackedInline):
|
|||||||
verbose_name_plural = "ВЧ загрузки"
|
verbose_name_plural = "ВЧ загрузки"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(ObjItem)
|
@admin.register(ObjItem)
|
||||||
class ObjectAdmin(admin.ModelAdmin):
|
class ObjectAdmin(admin.ModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
@@ -430,6 +431,8 @@ class ObjectAdmin(admin.ModelAdmin):
|
|||||||
"distance_geo_kup",
|
"distance_geo_kup",
|
||||||
"distance_geo_valid",
|
"distance_geo_valid",
|
||||||
"distance_kup_valid",
|
"distance_kup_valid",
|
||||||
|
"created_at",
|
||||||
|
"updated_at",
|
||||||
)
|
)
|
||||||
list_display_links = ("name",)
|
list_display_links = ("name",)
|
||||||
list_filter = (
|
list_filter = (
|
||||||
@@ -452,18 +455,28 @@ class ObjectAdmin(admin.ModelAdmin):
|
|||||||
ordering = ("name",)
|
ordering = ("name",)
|
||||||
inlines = [ParameterObjItemInline, GeoInline]
|
inlines = [ParameterObjItemInline, GeoInline]
|
||||||
actions = [show_on_map]
|
actions = [show_on_map]
|
||||||
|
readonly_fields = ('created_at', 'created_by', 'updated_at', 'updated_by')
|
||||||
|
|
||||||
|
|
||||||
def get_queryset(self, request):
|
def get_queryset(self, request):
|
||||||
qs = super().get_queryset(request)
|
qs = super().get_queryset(request)
|
||||||
return qs.select_related('geo_obj').prefetch_related(
|
return qs.select_related('geo_obj', 'created_by', 'updated_by').prefetch_related(
|
||||||
'parameters_obj__id_satellite',
|
'parameters_obj__id_satellite',
|
||||||
'parameters_obj__polarization',
|
'parameters_obj__polarization',
|
||||||
'parameters_obj__modulation',
|
'parameters_obj__modulation',
|
||||||
'parameters_obj__standard'
|
'parameters_obj__standard'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def get_readonly_fields(self, request, obj=None):
|
||||||
|
# Always make these fields readonly to preserve tracking
|
||||||
|
return self.readonly_fields
|
||||||
|
|
||||||
|
def save_model(self, request, obj, form, change):
|
||||||
|
if not change:
|
||||||
|
if not obj.created_by_id:
|
||||||
|
obj.created_by = request.user.customuser if hasattr(request.user, 'customuser') else None
|
||||||
|
obj.updated_by = request.user.customuser if hasattr(request.user, 'customuser') else None
|
||||||
|
super().save_model(request, obj, form, change)
|
||||||
|
|
||||||
def sat_name(self, obj):
|
def sat_name(self, obj):
|
||||||
param = next(iter(obj.parameters_obj.all()), None)
|
param = next(iter(obj.parameters_obj.all()), None)
|
||||||
if param and param.id_satellite:
|
if param and param.id_satellite:
|
||||||
|
|||||||
@@ -4,3 +4,6 @@ from django.apps import AppConfig
|
|||||||
class MainappConfig(AppConfig):
|
class MainappConfig(AppConfig):
|
||||||
default_auto_field = 'django.db.models.BigAutoField'
|
default_auto_field = 'django.db.models.BigAutoField'
|
||||||
name = 'mainapp'
|
name = 'mainapp'
|
||||||
|
|
||||||
|
def ready(self):
|
||||||
|
import mainapp.signals # noqa
|
||||||
|
|||||||
20
dbapp/mainapp/management/commands/create_user_profiles.py
Normal file
20
dbapp/mainapp/management/commands/create_user_profiles.py
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
from mainapp.models import CustomUser
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = 'Create CustomUser profiles for existing users who do not have them'
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
# Find all users who don't have a CustomUser profile
|
||||||
|
for user in User.objects.all():
|
||||||
|
if not hasattr(user, 'customuser'):
|
||||||
|
custom_user = CustomUser.objects.create(user=user)
|
||||||
|
self.stdout.write(
|
||||||
|
self.style.SUCCESS(f'Created CustomUser for {user.username}')
|
||||||
|
)
|
||||||
|
|
||||||
|
self.stdout.write(
|
||||||
|
self.style.SUCCESS('Successfully ensured all users have CustomUser profiles')
|
||||||
|
)
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
# Generated by Django 5.2.7 on 2025-10-13 12:47
|
# Generated by Django 5.2.7 on 2025-10-31 13:36
|
||||||
|
|
||||||
import django.contrib.gis.db.models.fields
|
import django.contrib.gis.db.models.fields
|
||||||
|
import django.contrib.gis.db.models.functions
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
|
import django.db.models.expressions
|
||||||
import mainapp.models
|
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
|
||||||
@@ -31,7 +33,7 @@ class Migration(migrations.Migration):
|
|||||||
name='Modulation',
|
name='Modulation',
|
||||||
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=20, unique=True, verbose_name='Модуляция')),
|
('name', models.CharField(db_index=True, max_length=20, unique=True, verbose_name='Модуляция')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'Модуляция',
|
'verbose_name': 'Модуляция',
|
||||||
@@ -53,7 +55,7 @@ class Migration(migrations.Migration):
|
|||||||
name='Satellite',
|
name='Satellite',
|
||||||
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(db_index=True, max_length=100, unique=True, verbose_name='Имя спутника')),
|
||||||
('norad', models.IntegerField(blank=True, null=True, verbose_name='NORAD ID')),
|
('norad', models.IntegerField(blank=True, null=True, verbose_name='NORAD ID')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
@@ -61,6 +63,18 @@ class Migration(migrations.Migration):
|
|||||||
'verbose_name_plural': 'Спутники',
|
'verbose_name_plural': 'Спутники',
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='SigmaParMark',
|
||||||
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('mark', models.BooleanField(blank=True, null=True, verbose_name='Наличие сигнала')),
|
||||||
|
('timestamp', models.DateTimeField(blank=True, null=True, verbose_name='Время')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'Отметка',
|
||||||
|
'verbose_name_plural': 'Отметки',
|
||||||
|
},
|
||||||
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Standard',
|
name='Standard',
|
||||||
fields=[
|
fields=[
|
||||||
@@ -85,35 +99,30 @@ class Migration(migrations.Migration):
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Geo',
|
name='ObjItem',
|
||||||
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')),
|
||||||
('timestamp', models.DateTimeField(blank=True, null=True, verbose_name='Время')),
|
('name', models.CharField(blank=True, db_index=True, max_length=100, null=True, verbose_name='Имя объекта')),
|
||||||
('coords', django.contrib.gis.db.models.fields.PointField(blank=True, null=True, srid=4326, verbose_name='Координата геолокации')),
|
('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='Пользователь')),
|
||||||
('location', models.CharField(blank=True, max_length=255, null=True, verbose_name='Метоположение')),
|
|
||||||
('comment', models.CharField(blank=True, max_length=255, verbose_name='Комментарий')),
|
|
||||||
('coords_kupsat', django.contrib.gis.db.models.fields.PointField(blank=True, null=True, srid=4326, verbose_name='Координаты Кубсата')),
|
|
||||||
('coords_valid', django.contrib.gis.db.models.fields.PointField(blank=True, null=True, srid=4326, verbose_name='Координаты оперативников')),
|
|
||||||
('is_average', models.BooleanField(blank=True, 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='Пользователь')),
|
|
||||||
('mirrors', models.ManyToManyField(related_name='geo_mirrors', to='mainapp.mirror', verbose_name='Зеркала')),
|
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'Гео',
|
'verbose_name': 'Объект',
|
||||||
'verbose_name_plural': 'Гео',
|
'verbose_name_plural': 'Объекты',
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Parameter',
|
name='Parameter',
|
||||||
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')),
|
||||||
('frequency', models.FloatField(blank=True, default=0, null=True, verbose_name='Частота, МГц')),
|
('frequency', models.FloatField(blank=True, db_index=True, default=0, null=True, verbose_name='Частота, МГц')),
|
||||||
('freq_range', models.FloatField(blank=True, default=0, null=True, verbose_name='Полоса частот, МГц')),
|
('freq_range', models.FloatField(blank=True, default=0, null=True, verbose_name='Полоса частот, МГц')),
|
||||||
('bod_velocity', models.FloatField(blank=True, default=0, 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='ОСШ')),
|
('snr', models.FloatField(blank=True, default=0, null=True, verbose_name='ОСШ')),
|
||||||
('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='Пользователь')),
|
('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='Пользователь')),
|
||||||
('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='Модуляция')),
|
('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='Модуляция')),
|
||||||
|
('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='Поляризация')),
|
('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='Спутник')),
|
||||||
('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='Стандарт')),
|
('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='Стандарт')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
@@ -122,26 +131,74 @@ class Migration(migrations.Migration):
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='ObjItem',
|
name='SourceType',
|
||||||
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=100, null=True, verbose_name='Имя объекта')),
|
('name', models.CharField(max_length=50, unique=True, verbose_name='Тип источника')),
|
||||||
('id_geo', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='objitems', to='mainapp.geo', 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='Гео')),
|
||||||
('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='Пользователь')),
|
|
||||||
('id_vch_load', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='objitems', to='mainapp.parameter', verbose_name='ВЧ загрузка')),
|
|
||||||
('id_satellite', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='objitems', to='mainapp.satellite', verbose_name='Спутник')),
|
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'verbose_name': 'Объект',
|
'verbose_name': 'Тип источника',
|
||||||
'verbose_name_plural': 'Объекты',
|
'verbose_name_plural': 'Типы источников',
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
migrations.AddConstraint(
|
migrations.CreateModel(
|
||||||
model_name='geo',
|
name='SigmaParameter',
|
||||||
constraint=models.UniqueConstraint(fields=('timestamp', 'coords'), name='unique_geo_combination'),
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('transfer', models.FloatField(choices=[(-1.0, '-'), (9750.0, '9750 МГц'), (10750.0, '10750 МГц')], default=-1.0, verbose_name='Перенос по частоте')),
|
||||||
|
('status', models.CharField(blank=True, max_length=20, null=True, verbose_name='Статус')),
|
||||||
|
('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='Полоса частот, МГц')),
|
||||||
|
('power', models.FloatField(blank=True, default=0, 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='ОСШ, Дб')),
|
||||||
|
('packets', models.BooleanField(blank=True, null=True, verbose_name='Пакетность')),
|
||||||
|
('datetime_begin', models.DateTimeField(blank=True, null=True, verbose_name='Время начала измерения')),
|
||||||
|
('datetime_end', models.DateTimeField(blank=True, null=True, verbose_name='Время окончания измерения')),
|
||||||
|
('id_satellite', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='sigmapar_sat', to='mainapp.satellite', 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='Модуляция')),
|
||||||
|
('parameter', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='sigma_parameter', to='mainapp.parameter', 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_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='Стандарт')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'verbose_name': 'ВЧ sigma',
|
||||||
|
'verbose_name_plural': 'ВЧ sigma',
|
||||||
|
},
|
||||||
),
|
),
|
||||||
migrations.AddConstraint(
|
migrations.CreateModel(
|
||||||
model_name='objitem',
|
name='Geo',
|
||||||
constraint=models.UniqueConstraint(fields=('id_vch_load', 'id_geo'), name='unique_objitem_combination'),
|
fields=[
|
||||||
|
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('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='Метоположение')),
|
||||||
|
('comment', models.CharField(blank=True, max_length=255, verbose_name='Комментарий')),
|
||||||
|
('coords_kupsat', django.contrib.gis.db.models.fields.PointField(blank=True, null=True, srid=4326, verbose_name='Координаты Кубсата')),
|
||||||
|
('coords_valid', django.contrib.gis.db.models.fields.PointField(blank=True, null=True, srid=4326, verbose_name='Координаты оперативников')),
|
||||||
|
('is_average', models.BooleanField(blank=True, 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='Расстояние между купсатом и гео, км')),
|
||||||
|
('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='Расстояние между гео и оперативным отделом, км')),
|
||||||
|
('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='Расстояние между купсатом и оперативным отделом, км')),
|
||||||
|
('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='Пользователь')),
|
||||||
|
('mirrors', models.ManyToManyField(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={
|
||||||
|
'verbose_name': 'Гео',
|
||||||
|
'verbose_name_plural': 'Гео',
|
||||||
|
'constraints': [models.UniqueConstraint(fields=('timestamp', 'coords'), name='unique_geo_combination')],
|
||||||
|
},
|
||||||
|
),
|
||||||
|
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'),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
# Generated by Django 5.2.7 on 2025-10-15 09:23
|
|
||||||
|
|
||||||
import django.contrib.gis.db.models.functions
|
|
||||||
import django.db.models.expressions
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('mainapp', '0001_initial'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
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='Расстояние между купсатом и гео'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
# 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='Изменен пользователем'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
# 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='Дата последнего изменения'),
|
||||||
|
),
|
||||||
|
]
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
# Generated by Django 5.2.7 on 2025-10-15 09:43
|
|
||||||
|
|
||||||
import django.contrib.gis.db.models.functions
|
|
||||||
import django.db.models.expressions
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('mainapp', '0002_geo_distance_coords_kup'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='geo',
|
|
||||||
name='distance_coords_valid',
|
|
||||||
field=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='Расстояние между гео и оперативным отделом, км'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
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='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='Расстояние между купсатом и гео, км'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
# Generated by Django 5.2.7 on 2025-10-16 12:50
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
import mainapp.models
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('mainapp', '0003_geo_distance_coords_valid_geo_distance_kup_valid_and_more'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='SigmaParameter',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('status', models.CharField(blank=True, max_length=20, null=True, verbose_name='Статус')),
|
|
||||||
('frequency', models.FloatField(blank=True, default=0, null=True, verbose_name='Частота, МГц')),
|
|
||||||
('freq_range', models.FloatField(blank=True, default=0, null=True, verbose_name='Полоса частот, МГц')),
|
|
||||||
('power', models.FloatField(blank=True, default=0, 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='ОСШ, Дб')),
|
|
||||||
('packets', models.BooleanField(blank=True, null=True, verbose_name='Пакетность')),
|
|
||||||
('datetime_begin', models.DateTimeField(blank=True, null=True, verbose_name='Время начала измерения')),
|
|
||||||
('datetime_end', models.DateTimeField(blank=True, null=True, 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='Модуляция')),
|
|
||||||
('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='Стандарт')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'ВЧ sigma',
|
|
||||||
'verbose_name_plural': 'ВЧ sigma',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
# Generated by Django 5.2.7 on 2025-10-20 07:57
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('mainapp', '0004_sigmaparameter'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='sigmaparameter',
|
|
||||||
name='id_satellite',
|
|
||||||
field=models.ForeignKey(default=2, on_delete=django.db.models.deletion.PROTECT, related_name='sigmapar_sat', to='mainapp.satellite', verbose_name='Спутник'),
|
|
||||||
preserve_default=False,
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
# Generated by Django 5.2.7 on 2025-10-20 11:57
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('mainapp', '0005_sigmaparameter_id_satellite'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='objitem',
|
|
||||||
name='id_satellite',
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='parameter',
|
|
||||||
name='id_satellite',
|
|
||||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='parameters', to='mainapp.satellite', verbose_name='Спутник'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
# Generated by Django 5.2.7 on 2025-10-20 11:58
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('mainapp', '0006_remove_objitem_id_satellite_parameter_id_satellite'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
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='Спутник'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
# Generated by Django 5.2.7 on 2025-10-22 11:21
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('mainapp', '0007_alter_parameter_id_satellite'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='geo',
|
|
||||||
name='timestamp',
|
|
||||||
field=models.DateTimeField(blank=True, db_index=True, null=True, verbose_name='Время'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='objitem',
|
|
||||||
name='name',
|
|
||||||
field=models.CharField(blank=True, db_index=True, max_length=100, null=True, verbose_name='Имя объекта'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='parameter',
|
|
||||||
name='frequency',
|
|
||||||
field=models.FloatField(blank=True, db_index=True, default=0, null=True, verbose_name='Частота, МГц'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='satellite',
|
|
||||||
name='name',
|
|
||||||
field=models.CharField(db_index=True, max_length=30, unique=True, verbose_name='Имя спутника'),
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='sigmaparameter',
|
|
||||||
name='frequency',
|
|
||||||
field=models.FloatField(blank=True, db_index=True, default=0, null=True, verbose_name='Частота, МГц'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
# Generated by Django 5.2.7 on 2025-10-22 12:08
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('mainapp', '0008_alter_geo_timestamp_alter_objitem_name_and_more'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='parameter',
|
|
||||||
name='id_sigma_parameter',
|
|
||||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='sigma_parameter', to='mainapp.sigmaparameter', verbose_name='ВЧ с sigma'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
# Generated by Django 5.2.7 on 2025-10-22 12:38
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('mainapp', '0009_parameter_id_sigma_parameter'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='SigmaParMark',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('mark', models.BooleanField(blank=True, null=True, verbose_name='Наличие сигнала')),
|
|
||||||
('timestamp', models.DateTimeField(blank=True, null=True, verbose_name='Время')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'Отметка',
|
|
||||||
'verbose_name_plural': 'Отметки',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='sigmaparameter',
|
|
||||||
name='mark',
|
|
||||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='mainapp.sigmaparmark', verbose_name='Отметка'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
# Generated by Django 5.2.7 on 2025-10-22 13:15
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('mainapp', '0010_sigmaparmark_sigmaparameter_mark'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='sigmaparameter',
|
|
||||||
name='mark',
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='sigmaparameter',
|
|
||||||
name='mark',
|
|
||||||
field=models.ManyToManyField(blank=True, null=True, to='mainapp.sigmaparmark', verbose_name='Отметка'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 5.2.7 on 2025-10-22 13:16
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('mainapp', '0011_remove_sigmaparameter_mark_sigmaparameter_mark'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='sigmaparameter',
|
|
||||||
name='mark',
|
|
||||||
field=models.ManyToManyField(blank=True, to='mainapp.sigmaparmark', verbose_name='Отметка'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
# Generated by Django 5.2.7 on 2025-10-22 13:48
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('mainapp', '0012_alter_sigmaparameter_mark'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
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'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 5.2.7 on 2025-10-23 08:12
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('mainapp', '0013_parameter_mainapp_par_id_sate_cbfab2_idx_and_more'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='modulation',
|
|
||||||
name='name',
|
|
||||||
field=models.CharField(db_index=True, max_length=20, unique=True, verbose_name='Модуляция'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
# Generated by Django 5.2.7 on 2025-10-23 09:40
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('mainapp', '0014_alter_modulation_name'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='parameter',
|
|
||||||
name='id_sigma_parameter',
|
|
||||||
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='sigma_parameter', to='mainapp.sigmaparameter', verbose_name='ВЧ с sigma'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
# Generated by Django 5.2.7 on 2025-10-23 09:58
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('mainapp', '0015_alter_parameter_id_sigma_parameter'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='parameter',
|
|
||||||
name='id_sigma_parameter',
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='sigmaparameter',
|
|
||||||
name='parameter',
|
|
||||||
field=models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='sigma_parameter', to='mainapp.parameter', verbose_name='ВЧ с sigma'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
# Generated by Django 5.2.7 on 2025-10-23 12:52
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('mainapp', '0016_remove_parameter_id_sigma_parameter_and_more'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
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='ВЧ'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
# Generated by Django 5.2.7 on 2025-10-27 13:10
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
import django.db.models.expressions
|
|
||||||
import mainapp.models
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('mainapp', '0017_alter_sigmaparameter_parameter'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
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='transfer',
|
|
||||||
field=models.FloatField(choices=[(-1.0, '-'), (9750.0, '9750 МГц'), (10750.0, '10750 МГц')], default=-1.0, verbose_name='Перенос по частоте'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='sigmaparameter',
|
|
||||||
name='transfer_frequency',
|
|
||||||
field=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, МГц'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 5.2.7 on 2025-10-28 05:41
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('mainapp', '0018_sigmaparameter_polarization_sigmaparameter_transfer_and_more'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='satellite',
|
|
||||||
name='name',
|
|
||||||
field=models.CharField(db_index=True, max_length=100, unique=True, verbose_name='Имя спутника'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
# Generated by Django 5.2.7 on 2025-10-29 14:00
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('mainapp', '0019_alter_satellite_name'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='SourceType',
|
|
||||||
fields=[
|
|
||||||
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('name', models.CharField(max_length=50, unique=True, verbose_name='Тип источника')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'Тип источника',
|
|
||||||
'verbose_name_plural': 'Типы источников',
|
|
||||||
},
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='objitem',
|
|
||||||
name='id_source_type',
|
|
||||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='objitems', to='mainapp.sourcetype', verbose_name='Тип источника'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
# Generated by Django 5.2.7 on 2025-10-30 06:40
|
|
||||||
|
|
||||||
import django.db.models.deletion
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('mainapp', '0020_sourcetype_objitem_id_source_type'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RemoveConstraint(
|
|
||||||
model_name='objitem',
|
|
||||||
name='unique_objitem_combination',
|
|
||||||
),
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='objitem',
|
|
||||||
name='id_geo',
|
|
||||||
),
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='objitem',
|
|
||||||
name='id_source_type',
|
|
||||||
),
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='objitem',
|
|
||||||
name='id_vch_load',
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='geo',
|
|
||||||
name='objitem',
|
|
||||||
field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='geo_obj', to='mainapp.objitem', verbose_name='Гео'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='parameter',
|
|
||||||
name='objitem',
|
|
||||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='parameters_obj', to='mainapp.objitem', verbose_name='Источник'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='sourcetype',
|
|
||||||
name='objitem',
|
|
||||||
field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='source_type_obj', to='mainapp.objitem', verbose_name='Гео'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
# Generated by Django 5.2.7 on 2025-10-30 07:05
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('mainapp', '0021_remove_objitem_unique_objitem_combination_and_more'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='parameter',
|
|
||||||
name='objitem',
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='parameter',
|
|
||||||
name='objitems',
|
|
||||||
field=models.ManyToManyField(blank=True, related_name='parameters_obj', to='mainapp.objitem', verbose_name='Источники'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -3,6 +3,7 @@ from django.contrib.auth.models import User
|
|||||||
from django.contrib.gis.db import models as gis
|
from django.contrib.gis.db import models as gis
|
||||||
from django.contrib.gis.db.models import functions
|
from django.contrib.gis.db.models import functions
|
||||||
from django.db.models import F, ExpressionWrapper
|
from django.db.models import F, ExpressionWrapper
|
||||||
|
from django.utils import timezone
|
||||||
|
|
||||||
def get_default_polarization():
|
def get_default_polarization():
|
||||||
obj, created = Polarization.objects.get_or_create(
|
obj, created = Polarization.objects.get_or_create(
|
||||||
@@ -113,9 +114,16 @@ class ObjItem(models.Model):
|
|||||||
# id_satellite = models.ForeignKey(Satellite, on_delete=models.PROTECT, related_name="objitems", verbose_name="Спутник")
|
# 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_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_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_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)
|
# 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):
|
def __str__(self):
|
||||||
return f"Объект {self.name}"
|
return f"Объект {self.name}"
|
||||||
|
|||||||
11
dbapp/mainapp/signals.py
Normal file
11
dbapp/mainapp/signals.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
from django.db.models.signals import post_save
|
||||||
|
from django.dispatch import receiver
|
||||||
|
from django.contrib.auth.models import User
|
||||||
|
from .models import CustomUser
|
||||||
|
|
||||||
|
|
||||||
|
@receiver(post_save, sender=User)
|
||||||
|
def create_or_update_user_profile(sender, instance, created, **kwargs):
|
||||||
|
if created:
|
||||||
|
CustomUser.objects.create(user=instance)
|
||||||
|
instance.customuser.save()
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
<span class="navbar-toggler-icon"></span>
|
<span class="navbar-toggler-icon"></span>
|
||||||
</button>
|
</button>
|
||||||
<div class="collapse navbar-collapse" id="navbarNav">
|
<div class="collapse navbar-collapse" id="navbarNav">
|
||||||
|
{% if user.is_authenticated %}
|
||||||
<ul class="navbar-nav me-auto">
|
<ul class="navbar-nav me-auto">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link" href="{% url 'home' %}">Объекты</a>
|
<a class="nav-link" href="{% url 'home' %}">Объекты</a>
|
||||||
@@ -39,6 +40,29 @@
|
|||||||
<a class="nav-link" href="{% url 'admin:index' %}">Админ панель</a>
|
<a class="nav-link" href="{% url 'admin:index' %}">Админ панель</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
<ul class="navbar-nav">
|
||||||
|
<li class="nav-item dropdown">
|
||||||
|
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown">
|
||||||
|
{% if user.first_name and user.last_name %}
|
||||||
|
{{ user.first_name }} {{ user.last_name }}
|
||||||
|
{% elif user.get_full_name %}
|
||||||
|
{{ user.get_full_name }}
|
||||||
|
{% else %}
|
||||||
|
{{ user.username }}
|
||||||
|
{% endif %}
|
||||||
|
</a>
|
||||||
|
<ul class="dropdown-menu dropdown-menu-end">
|
||||||
|
<li><a class="dropdown-item" href="{% url 'logout' %}">Выйти</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
{% else %}
|
||||||
|
<ul class="navbar-nav ms-auto">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="{% url 'login' %}">Войти</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|||||||
19
dbapp/mainapp/templates/mainapp/login_required.html
Normal file
19
dbapp/mainapp/templates/mainapp/login_required.html
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{% extends 'mainapp/base.html' %}
|
||||||
|
|
||||||
|
{% block title %}Войдите в систему{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container mt-5">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body text-center">
|
||||||
|
<h2 class="card-title">Требуется авторизация</h2>
|
||||||
|
<p class="card-text">Для просмотра содержимого сайта необходимо войти в систему.</p>
|
||||||
|
<a href="{% url 'login' %}" class="btn btn-primary">Войти</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@@ -16,13 +16,84 @@
|
|||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="d-flex flex-wrap align-items-center gap-3">
|
<div class="d-flex flex-wrap align-items-center gap-3">
|
||||||
<div style="min-width: 300px; flex-grow: 1;">
|
<!-- Search bar made more compact -->
|
||||||
<label for="toolbar-search" class="form-label mb-0">Поиск:</label>
|
<div style="min-width: 200px; flex-grow: 1; max-width: 400px;">
|
||||||
<input type="text" id="toolbar-search" class="form-control" placeholder="Поиск по имени, местоположению..." value="{{ search_query|default:'' }}">
|
<div class="input-group">
|
||||||
|
<input type="text" id="toolbar-search" class="form-control" placeholder="Поиск..." value="{{ search_query|default:'' }}">
|
||||||
|
<button type="button" class="btn btn-outline-primary" onclick="performSearch()">Найти</button>
|
||||||
|
<button type="button" class="btn btn-outline-secondary" onclick="clearSearch()">Очистить</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Action buttons bar -->
|
||||||
|
<div class="d-flex gap-2">
|
||||||
|
<button type="button" class="btn btn-success btn-sm" title="Добавить">
|
||||||
|
<i class="bi bi-plus-circle"></i> Добавить
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-info btn-sm" title="Изменить">
|
||||||
|
<i class="bi bi-pencil"></i> Изменить
|
||||||
|
</button>
|
||||||
|
<button type="button" class="btn btn-danger btn-sm" title="Удалить">
|
||||||
|
<i class="bi bi-trash"></i> Удалить
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Items per page select moved here -->
|
||||||
|
<div>
|
||||||
|
<label for="items-per-page" class="form-label mb-0">Показать:</label>
|
||||||
|
<select name="items_per_page" id="items-per-page" class="form-select form-select-sm d-inline-block" style="width: auto;" onchange="updateItemsPerPage()">
|
||||||
|
{% for option in available_items_per_page %}
|
||||||
|
<option value="{{ option }}" {% if option == items_per_page %}selected{% endif %}>
|
||||||
|
{{ option }}
|
||||||
|
</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Pagination moved here -->
|
||||||
<div class="ms-auto">
|
<div class="ms-auto">
|
||||||
<button type="button" class="btn btn-outline-primary" onclick="performSearch()">Найти</button>
|
{% if page_obj.paginator.num_pages > 1 %}
|
||||||
<button type="button" class="btn btn-outline-secondary" onclick="clearSearch()">Очистить</button>
|
<nav aria-label="Page navigation" class="d-flex align-items-center">
|
||||||
|
<ul class="pagination mb-0">
|
||||||
|
{% if page_obj.has_previous %}
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link" href="?{% for key, value in request.GET.items %}{% if key != 'page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}page=1" title="Первая"><<</a>
|
||||||
|
</li>
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link" href="?{% for key, value in request.GET.items %}{% if key != 'page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}page={{ page_obj.previous_page_number }}" title="Предыдущая"><</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% for num in page_obj.paginator.page_range %}
|
||||||
|
{% if page_obj.number == num %}
|
||||||
|
<li class="page-item active">
|
||||||
|
<span class="page-link">{{ num }}</span>
|
||||||
|
</li>
|
||||||
|
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link" href="?{% for key, value in request.GET.items %}{% if key != 'page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}page={{ num }}">{{ num }}</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% if page_obj.has_next %}
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link" href="?{% for key, value in request.GET.items %}{% if key != 'page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}page={{ page_obj.next_page_number }}" title="Следующая">></a>
|
||||||
|
</li>
|
||||||
|
<li class="page-item">
|
||||||
|
<a class="page-link" href="?{% for key, value in request.GET.items %}{% if key != 'page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}page={{ page_obj.paginator.num_pages }}" title="Последняя">>></a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<!-- Pagination Info -->
|
||||||
|
{% if page_obj %}
|
||||||
|
<div class="ms-3 text-muted small">
|
||||||
|
{{ page_obj.start_index }}-{{ page_obj.end_index }} из {{ page_obj.paginator.count }}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -32,7 +103,7 @@
|
|||||||
|
|
||||||
<div class="row g-3">
|
<div class="row g-3">
|
||||||
<!-- Filters Sidebar - Made narrower -->
|
<!-- Filters Sidebar - Made narrower -->
|
||||||
<div class="col-md-2">
|
<div class="col-md-auto">
|
||||||
<div class="card h-100">
|
<div class="card h-100">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h5 class="card-title">Фильтры</h5>
|
<h5 class="card-title">Фильтры</h5>
|
||||||
@@ -152,18 +223,6 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Items Per Page -->
|
|
||||||
<div class="mb-2">
|
|
||||||
<label for="items-per-page" class="form-label">Элементов:</label>
|
|
||||||
<select name="items_per_page" id="items-per-page" class="form-select form-select-sm" onchange="document.getElementById('filter-form').submit();">
|
|
||||||
{% for option in available_items_per_page %}
|
|
||||||
<option value="{{ option }}" {% if option == items_per_page %}selected{% endif %}>
|
|
||||||
{{ option }}
|
|
||||||
</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Apply Filters and Reset Buttons -->
|
<!-- Apply Filters and Reset Buttons -->
|
||||||
<div class="d-grid gap-2 mt-2">
|
<div class="d-grid gap-2 mt-2">
|
||||||
<button type="submit" class="btn btn-primary btn-sm">Применить</button>
|
<button type="submit" class="btn btn-primary btn-sm">Применить</button>
|
||||||
@@ -175,7 +234,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Main Table -->
|
<!-- Main Table -->
|
||||||
<div class="col-md-10">
|
<div class="col-md">
|
||||||
<div class="card h-100">
|
<div class="card h-100">
|
||||||
<div class="card-body p-0">
|
<div class="card-body p-0">
|
||||||
<div class="table-responsive" style="max-height: 75vh; overflow-y: auto;">
|
<div class="table-responsive" style="max-height: 75vh; overflow-y: auto;">
|
||||||
@@ -189,8 +248,8 @@
|
|||||||
<th scope="col">Спутник</th>
|
<th scope="col">Спутник</th>
|
||||||
<th scope="col">Част, МГц</th>
|
<th scope="col">Част, МГц</th>
|
||||||
<th scope="col">Полоса, МГц</th>
|
<th scope="col">Полоса, МГц</th>
|
||||||
<th scope="col">Поляр</th>
|
<th scope="col">Поляризация</th>
|
||||||
<th scope="col">Сим. v</th>
|
<th scope="col">Сим. V</th>
|
||||||
<th scope="col">Модул</th>
|
<th scope="col">Модул</th>
|
||||||
<th scope="col">ОСШ</th>
|
<th scope="col">ОСШ</th>
|
||||||
<th scope="col">Геолокация</th>
|
<th scope="col">Геолокация</th>
|
||||||
@@ -199,6 +258,8 @@
|
|||||||
<th scope="col">Гео-куб, км</th>
|
<th scope="col">Гео-куб, км</th>
|
||||||
<th scope="col">Гео-опер, км</th>
|
<th scope="col">Гео-опер, км</th>
|
||||||
<th scope="col">Куб-опер, км</th>
|
<th scope="col">Куб-опер, км</th>
|
||||||
|
<th scope="col">Обновлено</th>
|
||||||
|
<th scope="col">Кем</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -221,10 +282,12 @@
|
|||||||
<td>{{ item.distance_geo_kup }}</td>
|
<td>{{ item.distance_geo_kup }}</td>
|
||||||
<td>{{ item.distance_geo_valid }}</td>
|
<td>{{ item.distance_geo_valid }}</td>
|
||||||
<td>{{ item.distance_kup_valid }}</td>
|
<td>{{ item.distance_kup_valid }}</td>
|
||||||
|
<td>{{ item.obj.updated_at|date:"d.m.Y H:i" }}</td>
|
||||||
|
<td>{{ item.obj.updated_by }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% empty %}
|
{% empty %}
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="15" class="text-center py-4">
|
<td colspan="17" class="text-center py-4">
|
||||||
{% if selected_satellite_id %}
|
{% if selected_satellite_id %}
|
||||||
Нет данных для выбранных фильтров
|
Нет данных для выбранных фильтров
|
||||||
{% else %}
|
{% else %}
|
||||||
@@ -236,50 +299,6 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Pagination -->
|
|
||||||
{% if page_obj.paginator.num_pages > 1 %}
|
|
||||||
<nav aria-label="Page navigation" class="px-3 pb-3">
|
|
||||||
<ul class="pagination justify-content-center">
|
|
||||||
{% if page_obj.has_previous %}
|
|
||||||
<li class="page-item">
|
|
||||||
<a class="page-link" href="?{% for key, value in request.GET.items %}{% if key != 'page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}page=1">Первая</a>
|
|
||||||
</li>
|
|
||||||
<li class="page-item">
|
|
||||||
<a class="page-link" href="?{% for key, value in request.GET.items %}{% if key != 'page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}page={{ page_obj.previous_page_number }}">Предыдущая</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% for num in page_obj.paginator.page_range %}
|
|
||||||
{% if page_obj.number == num %}
|
|
||||||
<li class="page-item active">
|
|
||||||
<span class="page-link">{{ num }}</span>
|
|
||||||
</li>
|
|
||||||
{% elif num > page_obj.number|add:'-3' and num < page_obj.number|add:'3' %}
|
|
||||||
<li class="page-item">
|
|
||||||
<a class="page-link" href="?{% for key, value in request.GET.items %}{% if key != 'page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}page={{ num }}">{{ num }}</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
{% if page_obj.has_next %}
|
|
||||||
<li class="page-item">
|
|
||||||
<a class="page-link" href="?{% for key, value in request.GET.items %}{% if key != 'page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}page={{ page_obj.next_page_number }}">Следующая</a>
|
|
||||||
</li>
|
|
||||||
<li class="page-item">
|
|
||||||
<a class="page-link" href="?{% for key, value in request.GET.items %}{% if key != 'page' %}{{ key }}={{ value }}&{% endif %}{% endfor %}page={{ page_obj.paginator.num_pages }}">Последняя</a>
|
|
||||||
</li>
|
|
||||||
{% endif %}
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- Pagination Info -->
|
|
||||||
{% if page_obj %}
|
|
||||||
<div class="px-3 pb-3 d-flex justify-content-between align-items-center">
|
|
||||||
<div>Показано {{ page_obj.start_index }}-{{ page_obj.end_index }} из {{ page_obj.paginator.count }} записей</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -417,6 +436,21 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
updateSatelliteSelection();
|
updateSatelliteSelection();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Function to update items per page
|
||||||
|
window.updateItemsPerPage = function() {
|
||||||
|
const itemsPerPageSelect = document.getElementById('items-per-page');
|
||||||
|
const currentParams = new URLSearchParams(window.location.search);
|
||||||
|
|
||||||
|
// Add or update the items_per_page parameter
|
||||||
|
currentParams.set('items_per_page', itemsPerPageSelect.value);
|
||||||
|
|
||||||
|
// Remove page parameter to reset to first page when changing items per page
|
||||||
|
currentParams.delete('page');
|
||||||
|
|
||||||
|
// Update URL and reload
|
||||||
|
window.location.search = currentParams.toString();
|
||||||
|
};
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
19
dbapp/mainapp/templates/registration/logged_out.html
Normal file
19
dbapp/mainapp/templates/registration/logged_out.html
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{% extends 'mainapp/base.html' %}
|
||||||
|
|
||||||
|
{% block title %}Выход{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container mt-5">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body text-center">
|
||||||
|
<h2 class="card-title">Вы вышли из системы</h2>
|
||||||
|
<p class="card-text">Вы успешно вышли из системы.</p>
|
||||||
|
<a href="{% url 'login' %}" class="btn btn-primary">Войти снова</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
43
dbapp/mainapp/templates/registration/login.html
Normal file
43
dbapp/mainapp/templates/registration/login.html
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
{% extends 'mainapp/base.html' %}
|
||||||
|
|
||||||
|
{% block title %}Вход в систему{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container mt-5">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<h2 class="card-title text-center">Вход в систему</h2>
|
||||||
|
<form method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="{{ form.username.id_for_label }}" class="form-label">Имя пользователя</label>
|
||||||
|
{{ form.username }}
|
||||||
|
</div>
|
||||||
|
<div class="mb-3">
|
||||||
|
<label for="{{ form.password.id_for_label }}" class="form-label">Пароль</label>
|
||||||
|
{{ form.password }}
|
||||||
|
</div>
|
||||||
|
{% if form.errors %}
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
{% for field in form %}
|
||||||
|
{% for error in field.errors %}
|
||||||
|
<p>{{ error }}</p>
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
{% for error in form.non_field_errors %}
|
||||||
|
<p>{{ error }}</p>
|
||||||
|
{% endfor %}
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<div class="d-grid">
|
||||||
|
<button type="submit" class="btn btn-primary">Войти</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
@@ -5,8 +5,9 @@ from . import views
|
|||||||
|
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('', views.ObjItemListView.as_view(), name='home'), # Make objitems the main page
|
path('', views.HomePageView.as_view(), name='home'), # Home page that redirects based on auth
|
||||||
path('actions/', views.HomePageView.as_view(), name='actions'), # Move actions to a separate page
|
path('objitems/', views.ObjItemListView.as_view(), name='objitem_list'), # Objects list page
|
||||||
|
path('actions/', views.ActionsPageView.as_view(), name='actions'), # Move actions to a separate page
|
||||||
path('excel-data', views.LoadExcelDataView.as_view(), name='load_excel_data'),
|
path('excel-data', views.LoadExcelDataView.as_view(), name='load_excel_data'),
|
||||||
path('satellites', views.AddSatellitesView.as_view(), name='add_sats'),
|
path('satellites', views.AddSatellitesView.as_view(), name='add_sats'),
|
||||||
path('api/locations/<int:sat_id>/geojson/', views.GetLocationsView.as_view(), name='locations_by_id'),
|
path('api/locations/<int:sat_id>/geojson/', views.GetLocationsView.as_view(), name='locations_by_id'),
|
||||||
@@ -17,7 +18,6 @@ urlpatterns = [
|
|||||||
path('vch-upload/', views.UploadVchLoadView.as_view(), name='vch_load'),
|
path('vch-upload/', views.UploadVchLoadView.as_view(), name='vch_load'),
|
||||||
path('vch-link/', views.LinkVchSigmaView.as_view(), name='link_vch_sigma'),
|
path('vch-link/', views.LinkVchSigmaView.as_view(), name='link_vch_sigma'),
|
||||||
path('kubsat-excel/', views.ProcessKubsatView.as_view(), name='kubsat_excel'),
|
path('kubsat-excel/', views.ProcessKubsatView.as_view(), name='kubsat_excel'),
|
||||||
path('objitems/', views.ObjItemListView.as_view(), name='objitem_list'),
|
|
||||||
# path('upload/', views.upload_file, name='upload_file'),
|
# path('upload/', views.upload_file, name='upload_file'),
|
||||||
|
|
||||||
]
|
]
|
||||||
@@ -120,7 +120,7 @@ def fill_data_from_df(df: pd.DataFrame, sat: Satellite):
|
|||||||
bod_velocity=v,
|
bod_velocity=v,
|
||||||
modulation=mod_obj,
|
modulation=mod_obj,
|
||||||
snr=snr,
|
snr=snr,
|
||||||
defaults={'id_user_add': CustomUser.objects.get(id=1)}
|
# defaults={'id_user_add': CustomUser.objects.get(id=1)}
|
||||||
)
|
)
|
||||||
|
|
||||||
geo, _ = Geo.objects.get_or_create(
|
geo, _ = Geo.objects.get_or_create(
|
||||||
@@ -131,8 +131,7 @@ def fill_data_from_df(df: pd.DataFrame, sat: Satellite):
|
|||||||
'coords_valid': valid_point,
|
'coords_valid': valid_point,
|
||||||
'location': location,
|
'location': location,
|
||||||
'comment': comment,
|
'comment': comment,
|
||||||
'is_average': (comment != -1.0),
|
'is_average': (comment != -1.0)
|
||||||
'id_user_add': CustomUser.objects.get(id=1)
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
geo.save()
|
geo.save()
|
||||||
@@ -150,23 +149,6 @@ def fill_data_from_df(df: pd.DataFrame, sat: Satellite):
|
|||||||
obj_item.parameters_obj.set([vch_load_obj])
|
obj_item.parameters_obj.set([vch_load_obj])
|
||||||
geo.objitem = obj_item
|
geo.objitem = obj_item
|
||||||
geo.save()
|
geo.save()
|
||||||
# else:
|
|
||||||
|
|
||||||
|
|
||||||
# obj_item, _ = ObjItem.objects.get_or_create(
|
|
||||||
# defaults={
|
|
||||||
# 'name': source,
|
|
||||||
# 'id_user_add': CustomUser.objects.get(id=1),
|
|
||||||
# # 'id_satellite': sat
|
|
||||||
# }
|
|
||||||
# )
|
|
||||||
# obj_item.save()
|
|
||||||
# obj_item.parameters_obj.set([vch_load_obj])
|
|
||||||
# if geo:
|
|
||||||
# obj_item.geo_obj = geo
|
|
||||||
# # или в зависимости от вашей модели Geo, вы можете установить обратную связь там:
|
|
||||||
# # geo.objitem = obj_item
|
|
||||||
# geo.save()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -262,7 +244,7 @@ def get_points_from_csv(file_content):
|
|||||||
polarization=pol_obj,
|
polarization=pol_obj,
|
||||||
frequency=row['freq'],
|
frequency=row['freq'],
|
||||||
freq_range=row['f_range'],
|
freq_range=row['f_range'],
|
||||||
defaults={'id_user_add': CustomUser.objects.get(id=1)}
|
# defaults={'id_user_add': CustomUser.objects.get(id=1)}
|
||||||
)
|
)
|
||||||
|
|
||||||
geo_obj, _ = Geo.objects.get_or_create(
|
geo_obj, _ = Geo.objects.get_or_create(
|
||||||
@@ -270,7 +252,7 @@ def get_points_from_csv(file_content):
|
|||||||
coords=Point(row['lon'], row['lat'], srid=4326),
|
coords=Point(row['lon'], row['lat'], srid=4326),
|
||||||
defaults={
|
defaults={
|
||||||
'is_average': False,
|
'is_average': False,
|
||||||
'id_user_add': CustomUser.objects.get(id=1),
|
# 'id_user_add': CustomUser.objects.get(id=1),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
geo_obj.mirrors.set(Mirror.objects.filter(name__in=mir_lst))
|
geo_obj.mirrors.set(Mirror.objects.filter(name__in=mir_lst))
|
||||||
@@ -282,7 +264,7 @@ def get_points_from_csv(file_content):
|
|||||||
if not existing_obj_items.exists():
|
if not existing_obj_items.exists():
|
||||||
obj_item = ObjItem.objects.create(
|
obj_item = ObjItem.objects.create(
|
||||||
name=row['obj'],
|
name=row['obj'],
|
||||||
id_user_add=CustomUser.objects.get(id=1)
|
# id_user_add=CustomUser.objects.get(id=1)
|
||||||
)
|
)
|
||||||
obj_item.parameters_obj.set([vch_load_obj])
|
obj_item.parameters_obj.set([vch_load_obj])
|
||||||
geo_obj.objitem = obj_item
|
geo_obj.objitem = obj_item
|
||||||
|
|||||||
@@ -3,10 +3,12 @@ from django.contrib import messages
|
|||||||
from django.http import JsonResponse, HttpResponse
|
from django.http import JsonResponse, HttpResponse
|
||||||
from django.views.decorators.http import require_GET
|
from django.views.decorators.http import require_GET
|
||||||
from django.contrib.admin.views.decorators import staff_member_required
|
from django.contrib.admin.views.decorators import staff_member_required
|
||||||
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
from django.views import View
|
from django.views import View
|
||||||
from django.views.generic import TemplateView, FormView
|
from django.views.generic import TemplateView, FormView
|
||||||
from django.contrib.auth.mixins import UserPassesTestMixin
|
from django.contrib.auth.mixins import UserPassesTestMixin, LoginRequiredMixin
|
||||||
|
from django.contrib.auth import logout
|
||||||
from django.db import models
|
from django.db import models
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
from .utils import (
|
from .utils import (
|
||||||
@@ -25,7 +27,7 @@ from io import BytesIO
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
class AddSatellitesView(View):
|
class AddSatellitesView(LoginRequiredMixin, View):
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
add_satellite_list()
|
add_satellite_list()
|
||||||
return redirect('home')
|
return redirect('home')
|
||||||
@@ -38,7 +40,7 @@ class AddSatellitesView(View):
|
|||||||
# print("Файл не найден")
|
# print("Файл не найден")
|
||||||
# return redirect('home')
|
# return redirect('home')
|
||||||
|
|
||||||
class AddTranspondersView(FormView):
|
class AddTranspondersView(LoginRequiredMixin, FormView):
|
||||||
template_name = 'mainapp/transponders_upload.html'
|
template_name = 'mainapp/transponders_upload.html'
|
||||||
form_class = UploadFileForm
|
form_class = UploadFileForm
|
||||||
|
|
||||||
@@ -58,11 +60,26 @@ class AddTranspondersView(FormView):
|
|||||||
messages.error(self.request, "Форма заполнена некорректно.")
|
messages.error(self.request, "Форма заполнена некорректно.")
|
||||||
return super().form_invalid(form)
|
return super().form_invalid(form)
|
||||||
|
|
||||||
class HomePageView(TemplateView):
|
from django.views.generic import View
|
||||||
template_name = 'mainapp/actions.html'
|
|
||||||
|
class ActionsPageView(View):
|
||||||
|
def get(self, request):
|
||||||
|
if request.user.is_authenticated:
|
||||||
|
return render(request, 'mainapp/actions.html')
|
||||||
|
else:
|
||||||
|
return render(request, 'mainapp/login_required.html')
|
||||||
|
|
||||||
|
|
||||||
class LoadExcelDataView(FormView):
|
class HomePageView(View):
|
||||||
|
def get(self, request):
|
||||||
|
if request.user.is_authenticated:
|
||||||
|
# Redirect to objitem list if authenticated
|
||||||
|
return redirect('objitem_list')
|
||||||
|
else:
|
||||||
|
return render(request, 'mainapp/login_required.html')
|
||||||
|
|
||||||
|
|
||||||
|
class LoadExcelDataView(LoginRequiredMixin, FormView):
|
||||||
template_name = 'mainapp/add_data_from_excel.html'
|
template_name = 'mainapp/add_data_from_excel.html'
|
||||||
form_class = LoadExcelData
|
form_class = LoadExcelData
|
||||||
|
|
||||||
@@ -94,7 +111,7 @@ from django.core.paginator import Paginator
|
|||||||
from django.db.models import Prefetch
|
from django.db.models import Prefetch
|
||||||
from .models import Satellite, ObjItem, Parameter, Geo
|
from .models import Satellite, ObjItem, Parameter, Geo
|
||||||
|
|
||||||
class GetLocationsView(View):
|
class GetLocationsView(LoginRequiredMixin, View):
|
||||||
def get(self, request, sat_id):
|
def get(self, request, sat_id):
|
||||||
locations = ObjItem.objects.filter(parameters_obj__id_satellite=sat_id)
|
locations = ObjItem.objects.filter(parameters_obj__id_satellite=sat_id)
|
||||||
if not locations:
|
if not locations:
|
||||||
@@ -122,7 +139,7 @@ class GetLocationsView(View):
|
|||||||
"features": features
|
"features": features
|
||||||
})
|
})
|
||||||
|
|
||||||
class LoadCsvDataView(FormView):
|
class LoadCsvDataView(LoginRequiredMixin, FormView):
|
||||||
template_name = 'mainapp/add_data_from_csv.html'
|
template_name = 'mainapp/add_data_from_csv.html'
|
||||||
form_class = LoadCsvData
|
form_class = LoadCsvData
|
||||||
|
|
||||||
@@ -196,17 +213,23 @@ class ShowMapView(UserPassesTestMixin, View):
|
|||||||
return render(request, 'admin/map_custom.html', context)
|
return render(request, 'admin/map_custom.html', context)
|
||||||
|
|
||||||
|
|
||||||
class ClusterTestView(View):
|
class ClusterTestView(LoginRequiredMixin, View):
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
objs = ObjItem.objects.filter(name__icontains="! Astra 4A 12654,040 [1,962] МГц H")
|
objs = ObjItem.objects.filter(name__icontains="! Astra 4A 12654,040 [1,962] МГц H")
|
||||||
coords = []
|
coords = []
|
||||||
for obj in objs:
|
for obj in objs:
|
||||||
coords.append((obj.id_geo.coords[1], obj.id_geo.coords[0]))
|
if obj.geo_obj and obj.geo_obj.coords:
|
||||||
|
coords.append((obj.geo_obj.coords.coords[1], obj.geo_obj.coords.coords[0]))
|
||||||
get_clusters(coords)
|
get_clusters(coords)
|
||||||
|
|
||||||
return JsonResponse({"success": "ок"})
|
return JsonResponse({"success": "ок"})
|
||||||
|
|
||||||
class UploadVchLoadView(FormView):
|
|
||||||
|
def custom_logout(request):
|
||||||
|
logout(request)
|
||||||
|
return redirect('home')
|
||||||
|
|
||||||
|
class UploadVchLoadView(LoginRequiredMixin, FormView):
|
||||||
template_name = 'mainapp/upload_html.html'
|
template_name = 'mainapp/upload_html.html'
|
||||||
form_class = UploadVchLoad
|
form_class = UploadVchLoad
|
||||||
|
|
||||||
@@ -227,7 +250,7 @@ class UploadVchLoadView(FormView):
|
|||||||
return super().form_invalid(form)
|
return super().form_invalid(form)
|
||||||
|
|
||||||
|
|
||||||
class LinkVchSigmaView(FormView):
|
class LinkVchSigmaView(LoginRequiredMixin, FormView):
|
||||||
template_name = 'mainapp/link_vch.html'
|
template_name = 'mainapp/link_vch.html'
|
||||||
form_class = VchLinkForm
|
form_class = VchLinkForm
|
||||||
|
|
||||||
@@ -245,7 +268,7 @@ class LinkVchSigmaView(FormView):
|
|||||||
return self.render_to_response(self.get_context_data(form=form))
|
return self.render_to_response(self.get_context_data(form=form))
|
||||||
|
|
||||||
|
|
||||||
class ProcessKubsatView(FormView):
|
class ProcessKubsatView(LoginRequiredMixin, FormView):
|
||||||
template_name = 'mainapp/process_kubsat.html'
|
template_name = 'mainapp/process_kubsat.html'
|
||||||
form_class = NewEventForm
|
form_class = NewEventForm
|
||||||
|
|
||||||
@@ -278,15 +301,16 @@ class ProcessKubsatView(FormView):
|
|||||||
messages.error(self.request, "Форма заполнена некорректно.")
|
messages.error(self.request, "Форма заполнена некорректно.")
|
||||||
return super().form_invalid(form)
|
return super().form_invalid(form)
|
||||||
|
|
||||||
class ObjItemListView(View):
|
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||||
|
|
||||||
|
class ObjItemListView(LoginRequiredMixin, View):
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
# Get satellites that have associated objects, sorted alphabetically
|
|
||||||
satellites = Satellite.objects.filter(parameters__objitems__isnull=False).distinct().order_by('name')
|
satellites = Satellite.objects.filter(parameters__objitems__isnull=False).distinct().order_by('name')
|
||||||
|
|
||||||
# Get selected satellite from query parameters
|
# Get selected satellite from query parameters
|
||||||
selected_sat_id = request.GET.get('satellite_id')
|
selected_sat_id = request.GET.get('satellite_id')
|
||||||
page_number = request.GET.get('page', 1)
|
page_number = request.GET.get('page', 1)
|
||||||
items_per_page = request.GET.get('items_per_page', '25') # Default to 25 items per page
|
items_per_page = request.GET.get('items_per_page', '50')
|
||||||
|
|
||||||
# Get filter parameters
|
# Get filter parameters
|
||||||
freq_min = request.GET.get('freq_min')
|
freq_min = request.GET.get('freq_min')
|
||||||
@@ -327,7 +351,8 @@ class ObjItemListView(View):
|
|||||||
# Start with the basic filter
|
# Start with the basic filter
|
||||||
objects = ObjItem.objects.select_related(
|
objects = ObjItem.objects.select_related(
|
||||||
'id_user_add__user',
|
'id_user_add__user',
|
||||||
'geo_obj'
|
'geo_obj',
|
||||||
|
'updated_by__user'
|
||||||
).prefetch_related(
|
).prefetch_related(
|
||||||
'parameters_obj__id_satellite',
|
'parameters_obj__id_satellite',
|
||||||
'parameters_obj__polarization',
|
'parameters_obj__polarization',
|
||||||
@@ -338,7 +363,8 @@ class ObjItemListView(View):
|
|||||||
# If no satellites are selected, start with all objects
|
# If no satellites are selected, start with all objects
|
||||||
objects = ObjItem.objects.select_related(
|
objects = ObjItem.objects.select_related(
|
||||||
'id_user_add__user',
|
'id_user_add__user',
|
||||||
'geo_obj'
|
'geo_obj',
|
||||||
|
'updated_by__user'
|
||||||
).prefetch_related(
|
).prefetch_related(
|
||||||
'parameters_obj__id_satellite',
|
'parameters_obj__id_satellite',
|
||||||
'parameters_obj__polarization',
|
'parameters_obj__polarization',
|
||||||
@@ -499,9 +525,9 @@ class ObjItemListView(View):
|
|||||||
'frequency': f"{param.frequency:.3f}" if param and param.frequency else "-",
|
'frequency': f"{param.frequency:.3f}" if param and param.frequency else "-",
|
||||||
'freq_range': f"{param.freq_range:.3f}" if param and param.freq_range else "-",
|
'freq_range': f"{param.freq_range:.3f}" if param and param.freq_range else "-",
|
||||||
'polarization': param.polarization.name if param and param.polarization else "-",
|
'polarization': param.polarization.name if param and param.polarization else "-",
|
||||||
'bod_velocity': f"{param.bod_velocity:.3f}" if param and param.bod_velocity else "-",
|
'bod_velocity': f"{param.bod_velocity:.0f}" if param and param.bod_velocity else "-",
|
||||||
'modulation': param.modulation.name if param and param.modulation else "-",
|
'modulation': param.modulation.name if param and param.modulation else "-",
|
||||||
'snr': f"{param.snr:.3f}" if param and param.snr else "-",
|
'snr': f"{param.snr:.0f}" if param and param.snr else "-",
|
||||||
'geo_coords': geo_coords,
|
'geo_coords': geo_coords,
|
||||||
'kupsat_coords': kupsat_coords,
|
'kupsat_coords': kupsat_coords,
|
||||||
'valid_coords': valid_coords,
|
'valid_coords': valid_coords,
|
||||||
@@ -522,7 +548,7 @@ class ObjItemListView(View):
|
|||||||
'page_obj': page_obj,
|
'page_obj': page_obj,
|
||||||
'processed_objects': processed_objects,
|
'processed_objects': processed_objects,
|
||||||
'items_per_page': items_per_page,
|
'items_per_page': items_per_page,
|
||||||
'available_items_per_page': [10, 25, 50, 100],
|
'available_items_per_page': [50, 100, 500, 1000],
|
||||||
# Filter values
|
# Filter values
|
||||||
'freq_min': freq_min,
|
'freq_min': freq_min,
|
||||||
'freq_max': freq_max,
|
'freq_max': freq_max,
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
# Generated by Django 5.2.7 on 2025-10-13 12:47
|
# Generated by Django 5.2.7 on 2025-10-31 13:36
|
||||||
|
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
|
import django.db.models.expressions
|
||||||
|
import django.db.models.functions.math
|
||||||
import mainapp.models
|
import mainapp.models
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
|
|
||||||
@@ -19,9 +21,11 @@ class Migration(migrations.Migration):
|
|||||||
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, max_length=30, null=True, verbose_name='Название транспондера')),
|
||||||
('frequency', models.FloatField(blank=True, null=True, verbose_name='Центральная частота')),
|
('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='Полоса')),
|
||||||
('zone_name', models.CharField(blank=True, max_length=60, null=True, verbose_name='Название зоны')),
|
('uplink', models.FloatField(blank=True, null=True, verbose_name='Uplink')),
|
||||||
|
('zone_name', models.CharField(blank=True, 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='Перенос')),
|
||||||
('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='Поляризация')),
|
('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='Поляризация')),
|
||||||
('sat_id', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='tran_satellite', to='mainapp.satellite', verbose_name='Спутник')),
|
('sat_id', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='tran_satellite', to='mainapp.satellite', verbose_name='Спутник')),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
# Generated by Django 5.2.7 on 2025-10-27 12:20
|
|
||||||
|
|
||||||
import django.db.models.expressions
|
|
||||||
import django.db.models.functions.math
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('mapsapp', '0001_initial'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='transponders',
|
|
||||||
name='frequency',
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='transponders',
|
|
||||||
name='downlink',
|
|
||||||
field=models.FloatField(blank=True, null=True, verbose_name='Downlink'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='transponders',
|
|
||||||
name='uplink',
|
|
||||||
field=models.FloatField(blank=True, null=True, verbose_name='Uplink'),
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='transponders',
|
|
||||||
name='transfer',
|
|
||||||
field=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='Расстояние между купсатом и гео, км'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
# Generated by Django 5.2.7 on 2025-10-27 13:10
|
|
||||||
|
|
||||||
import django.db.models.expressions
|
|
||||||
import django.db.models.functions.math
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('mapsapp', '0002_remove_transponders_frequency_transponders_downlink_and_more'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='transponders',
|
|
||||||
name='transfer',
|
|
||||||
field=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='Перенос'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 5.2.7 on 2025-10-28 05:44
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('mapsapp', '0003_alter_transponders_transfer'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='transponders',
|
|
||||||
name='zone_name',
|
|
||||||
field=models.CharField(blank=True, max_length=255, null=True, verbose_name='Название зоны'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 5.2.7 on 2025-10-29 14:00
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('mapsapp', '0004_alter_transponders_zone_name'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='transponders',
|
|
||||||
name='frequency_range',
|
|
||||||
field=models.FloatField(blank=True, null=True, verbose_name='Полоса'),
|
|
||||||
),
|
|
||||||
]
|
|
||||||
Reference in New Issue
Block a user