From a7e8f81ef3569d1cf6cfae4c0a3648128dcfd52b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=BE=D1=88=D0=BA=D0=B8=D0=BD=20=D0=A1=D0=B5=D1=80?= =?UTF-8?q?=D0=B3=D0=B5=D0=B9?= Date: Wed, 12 Nov 2025 22:03:00 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9F=D0=BE=D0=BF=D1=80=D0=B0=D0=B2=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=B0=D0=B4=D0=BC=D0=B8=D0=BD=D0=BA=D1=83=20=D0=B4?= =?UTF-8?q?=D0=BB=D1=8F=20=D0=BD=D0=BE=D0=B2=D0=BE=D0=B9=20=D0=BC=D0=BE?= =?UTF-8?q?=D0=B4=D0=B5=D0=BB=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dbapp/mainapp/admin.py | 62 +++++++++++++++++++++++++++++++++++++++++ dbapp/mainapp/models.py | 25 +++++++++-------- 2 files changed, 75 insertions(+), 12 deletions(-) diff --git a/dbapp/mainapp/admin.py b/dbapp/mainapp/admin.py index 5730a07..a8a852b 100644 --- a/dbapp/mainapp/admin.py +++ b/dbapp/mainapp/admin.py @@ -854,6 +854,67 @@ class BandAdmin(ImportExportActionModelAdmin, BaseAdmin): ordering = ("name",) +class ObjItemInline(admin.TabularInline): + """Inline для отображения объектов ObjItem в Source.""" + model = ObjItem + fk_name = "source" + extra = 0 + can_delete = False + verbose_name = "Объект" + verbose_name_plural = "Объекты" + + fields = ("name", "get_geo_coords", "get_satellite", "get_frequency", "get_polarization", "updated_at") + readonly_fields = ("name", "get_geo_coords", "get_satellite", "get_frequency", "get_polarization", "updated_at") + + def get_queryset(self, request): + """Оптимизированный queryset с предзагрузкой связанных объектов.""" + qs = super().get_queryset(request) + return qs.select_related( + 'geo_obj', + 'parameter_obj', + 'parameter_obj__id_satellite', + 'parameter_obj__polarization' + ) + + def get_geo_coords(self, obj): + """Отображает координаты из связанной модели Geo.""" + if not obj or not hasattr(obj, 'geo_obj'): + return "-" + geo = obj.geo_obj + if not geo or not geo.coords: + return "-" + longitude = geo.coords.coords[0] + latitude = geo.coords.coords[1] + lon = f"{longitude}E" if longitude > 0 else f"{abs(longitude)}W" + lat = f"{latitude}N" if latitude > 0 else f"{abs(latitude)}S" + return f"{lat} {lon}" + get_geo_coords.short_description = "Координаты" + + def get_satellite(self, obj): + """Отображает спутник из связанного параметра.""" + if hasattr(obj, 'parameter_obj') and obj.parameter_obj and obj.parameter_obj.id_satellite: + return obj.parameter_obj.id_satellite.name + return "-" + get_satellite.short_description = "Спутник" + + def get_frequency(self, obj): + """Отображает частоту из связанного параметра.""" + if hasattr(obj, 'parameter_obj') and obj.parameter_obj: + return obj.parameter_obj.frequency + return "-" + get_frequency.short_description = "Частота, МГц" + + def get_polarization(self, obj): + """Отображает поляризацию из связанного параметра.""" + if hasattr(obj, 'parameter_obj') and obj.parameter_obj and obj.parameter_obj.polarization: + return obj.parameter_obj.polarization.name + return "-" + get_polarization.short_description = "Поляризация" + + def has_add_permission(self, request, obj=None): + return False + + @admin.register(Source) class SourceAdmin(ImportExportActionModelAdmin, LeafletGeoAdmin, BaseAdmin): """Админ-панель для модели Source.""" @@ -864,6 +925,7 @@ class SourceAdmin(ImportExportActionModelAdmin, LeafletGeoAdmin, BaseAdmin): ) ordering = ("-created_at",) readonly_fields = ("created_at", "created_by", "updated_at", "updated_by") + inlines = [ObjItemInline] fieldsets = ( ("Координаты: геолокация", { diff --git a/dbapp/mainapp/models.py b/dbapp/mainapp/models.py index 42b455b..f254b2e 100644 --- a/dbapp/mainapp/models.py +++ b/dbapp/mainapp/models.py @@ -201,6 +201,7 @@ class Standard(models.Model): verbose_name_plural = "Стандарты" ordering = ["name"] + class Band(models.Model): name = models.CharField( max_length=50, @@ -209,14 +210,10 @@ class Band(models.Model): help_text="Название диапазона", ) border_start = models.FloatField( - blank=True, - null=True, - verbose_name="Нижняя граница диапазона, МГц" + blank=True, null=True, verbose_name="Нижняя граница диапазона, МГц" ) border_end = models.FloatField( - blank=True, - null=True, - verbose_name="Верхняя граница диапазона, МГц" + blank=True, null=True, verbose_name="Верхняя граница диапазона, МГц" ) def __str__(self): @@ -319,8 +316,6 @@ class Satellite(models.Model): ordering = ["name"] - - class ObjItemQuerySet(models.QuerySet): """Custom QuerySet для модели ObjItem с оптимизированными запросами""" @@ -374,6 +369,13 @@ class Source(models.Model): Модель источника сигнала. """ + coords_average = gis.PointField( + srid=4326, + null=True, + blank=True, + verbose_name="Координаты ГЛ", + help_text="Усреднённые координаты, полученные от в ходе геолокации (WGS84)", + ) coords_kupsat = gis.PointField( srid=4326, null=True, @@ -425,7 +427,6 @@ class Source(models.Model): help_text="Пользователь, последним изменивший запись", ) - class Meta: verbose_name = "Источник" verbose_name_plural = "Источники" @@ -452,12 +453,12 @@ class ObjItem(models.Model): on_delete=models.CASCADE, null=True, verbose_name="ИРИ", - related_name="source", + related_name="source_objitems", ) transponder = models.ForeignKey( "mapsapp.Transponders", on_delete=models.SET_NULL, - related_name="transponder", + related_name="transponder_objitems", null=True, blank=True, verbose_name="Транспондер", @@ -596,7 +597,7 @@ class Parameter(models.Model): verbose_name="Объект", null=True, blank=True, - help_text="Связанный объект" + help_text="Связанный объект", ) # id_sigma_parameter = models.ManyToManyField(SigmaParameter, on_delete=models.SET_NULL, related_name="sigma_parameter", verbose_name="ВЧ с sigma", null=True, blank=True) # id_sigma_parameter = models.ManyToManyField(SigmaParameter, verbose_name="ВЧ с sigma", null=True, blank=True)