# admin.py from django.contrib import admin from .models import ( Polarization, Modulation, Standard, SigmaParMark, SigmaParameter, SourceType, Parameter, Satellite, Mirror, Geo, ObjItem, CustomUser ) from leaflet.admin import LeafletGeoAdmin from django import forms from django.contrib.auth.models import Group from django.contrib.auth.admin import UserAdmin as BaseUserAdmin from django.contrib.auth.models import User from django.contrib.gis.db import models as gis from django.shortcuts import redirect from django.urls import reverse from django.utils import timezone from rangefilter.filters import ( DateRangeFilterBuilder, DateTimeRangeFilterBuilder, NumericRangeFilterBuilder, DateRangeQuickSelectListFilterBuilder, ) from dynamic_raw_id.admin import DynamicRawIDMixin from more_admin_filters import MultiSelectDropdownFilter, MultiSelectFilter, MultiSelectRelatedDropdownFilter from import_export.admin import ImportExportActionModelAdmin from .filters import GeoKupDistanceFilter, GeoValidDistanceFilter, UniqueToggleFilter, HasSigmaParameterFilter admin.site.site_title = "Геолокация" admin.site.site_header = "Geolocation" admin.site.index_title = "Geo" admin.site.unregister(User) admin.site.unregister(Group) class LocationForm(forms.ModelForm): latitude_geo = forms.FloatField(required=False, label="Широта") longitude_geo = forms.FloatField(required=False, label="Долгота") latitude_kupsat = forms.FloatField(required=False, label="Широта") longitude_kupsat = forms.FloatField(required=False, label="Долгота") latitude_valid = forms.FloatField(required=False, label="Широта") longitude_valid = forms.FloatField(required=False, label="Долгота") class Meta: model = Geo fields = '__all__' def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) if self.instance and self.instance.coords: self.fields['latitude_geo'].initial = self.instance.coords[1] self.fields['longitude_geo'].initial = self.instance.coords[0] if self.instance and self.instance.coords_kupsat: self.fields['latitude_kupsat'].initial = self.instance.coords_kupsat[1] self.fields['longitude_kupsat'].initial = self.instance.coords_kupsat[0] if self.instance and self.instance.coords_valid: self.fields['latitude_valid'].initial = self.instance.coords_valid[1] self.fields['longitude_valid'].initial = self.instance.coords_valid[0] def save(self, commit=True): instance = super().save(commit=False) from django.contrib.gis.geos import Point lat = self.cleaned_data.get('latitude_geo') lon = self.cleaned_data.get('longitude_geo') if lat is not None and lon is not None: instance.coords = Point(lon, lat, srid=4326) lat = self.cleaned_data.get('latitude_kupsat') lon = self.cleaned_data.get('longitude_kupsat') if lat is not None and lon is not None: instance.coords_kupsat = Point(lon, lat, srid=4326) lat = self.cleaned_data.get('latitude_valid') lon = self.cleaned_data.get('longitude_valid') if lat is not None and lon is not None: instance.coords_valid = Point(lon, lat, srid=4326) if commit: instance.save() return instance 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): inlines = [CustomUserInline] admin.site.register(User, UserAdmin) @admin.register(SigmaParMark) class SigmaParMarkAdmin(admin.ModelAdmin): list_display = ("mark", "timestamp") search_fields = ("mark", ) ordering = ("timestamp",) @admin.register(Polarization) class PolarizationAdmin(admin.ModelAdmin): list_display = ("name",) search_fields = ("name",) ordering = ("name",) @admin.register(Modulation) class ModulationAdmin(admin.ModelAdmin): list_display = ("name",) search_fields = ("name",) ordering = ("name",) @admin.register(SourceType) class ModulationAdmin(admin.ModelAdmin): list_display = ("name",) search_fields = ("name",) ordering = ("name",) @admin.register(Standard) class StandardAdmin(admin.ModelAdmin): list_display = ("name",) search_fields = ("name",) ordering = ("name",) class SigmaParameterInline(admin.StackedInline): model = SigmaParameter extra = 0 autocomplete_fields = ['mark'] readonly_fields = ( "datetime_begin", "datetime_end", ) def has_add_permission(self, request, obj=None): return False @admin.register(Parameter) class ParameterAdmin(ImportExportActionModelAdmin, admin.ModelAdmin): list_display = ( "id_satellite", "frequency", "freq_range", "polarization", "modulation", "bod_velocity", "snr", "standard", "sigma_parameter" ) # fields = ( "id_satellite", # "frequency", # "freq_range", # "polarization", # "modulation", # "bod_velocity", # "snr", # "standard", # "id_sigma_parameter") list_display_links = ("frequency", "id_satellite", ) list_filter = ( HasSigmaParameterFilter, ("id_satellite", MultiSelectRelatedDropdownFilter), ("polarization__name", MultiSelectDropdownFilter), ("modulation", MultiSelectRelatedDropdownFilter), ("standard", MultiSelectRelatedDropdownFilter), ("frequency", NumericRangeFilterBuilder()), ("freq_range", NumericRangeFilterBuilder()), ("snr", NumericRangeFilterBuilder()), ) search_fields = ( "id_satellite", "frequency", "freq_range", "bod_velocity", "snr", "modulation__name", "polarization__name", "standard__name", ) ordering = ("frequency",) list_select_related = ("polarization", "modulation", "standard", "id_satellite",) # raw_id_fields = ("id_sigma_parameter", ) inlines = [SigmaParameterInline] # autocomplete_fields = ("id_sigma_parameter", ) def sigma_parameter(self, obj): sigma_obj = obj.sigma_parameter.all() if sigma_obj: return f"{sigma_obj[0].frequency}: {sigma_obj[0].freq_range}" return '-' sigma_parameter.short_description = "ВЧ sigma" @admin.register(SigmaParameter) class SigmaParameterAdmin(ImportExportActionModelAdmin, admin.ModelAdmin): list_display = ( "id_satellite", # "status", "frequency", "transfer_frequency", "freq_range", # "power", "polarization", "modulation", "bod_velocity", "snr", # "standard", "parameter", # "packets", "datetime_begin", "datetime_end", ) readonly_fields = ( "datetime_begin", "datetime_end", "transfer_frequency" ) list_display_links = ("id_satellite",) list_filter = ( ("id_satellite__name", MultiSelectDropdownFilter), ("modulation__name", MultiSelectDropdownFilter), ("standard__name", MultiSelectDropdownFilter), ("frequency", NumericRangeFilterBuilder()), ("freq_range", NumericRangeFilterBuilder()), ("snr", NumericRangeFilterBuilder()), ) search_fields = ( "id_satellite__name", "frequency", "freq_range", "bod_velocity", "snr", "modulation__name", "standard__name", ) autocomplete_fields = ('mark',) ordering = ("frequency",) list_select_related = ("modulation", "standard", "id_satellite", "parameter") prefetch_related = ("mark",) @admin.register(Satellite) class SatelliteAdmin(admin.ModelAdmin): list_display = ("name",) search_fields = ("name",) ordering = ("name",) @admin.register(Mirror) class MirrorAdmin(ImportExportActionModelAdmin, admin.ModelAdmin): list_display = ("name",) search_fields = ("name",) ordering = ("name",) @admin.register(Geo) class GeoAdmin(ImportExportActionModelAdmin, LeafletGeoAdmin): form = LocationForm readonly_fields = ("distance_coords_kup", "distance_coords_valid", "distance_kup_valid") fieldsets = ( ("Основная информация", { "fields": ("mirrors", "location", "distance_coords_kup", "distance_coords_valid", "distance_kup_valid", "timestamp", "comment", "id_user_add") }), ("Координаты: геолокация", { "fields": ("longitude_geo", "latitude_geo", "coords"), }), ("Координаты: Кубсат", { "fields": ("longitude_kupsat", "latitude_kupsat", "coords_kupsat"), }), ("Координаты: Оперативный отдел", { "fields": ("longitude_valid", "latitude_valid", "coords_valid"), }), ) list_display = ( "formatted_timestamp", "location", "mirrors_names", "geo_coords", "kupsat_coords", "valid_coords", "is_average", ) autocomplete_fields = ('mirrors',) list_display_links = ("formatted_timestamp",) list_filter = ( ("mirrors", MultiSelectRelatedDropdownFilter), "is_average", ("location", MultiSelectDropdownFilter), ("timestamp", DateRangeQuickSelectListFilterBuilder()), ("id_user_add", MultiSelectRelatedDropdownFilter), ) search_fields = ( "mirrors__name", "location", "coords", "coords_kupsat", "coords_valid" ) list_select_related = ("id_user_add", ) prefetch_related = ("mirrors", ) settings_overrides = { 'DEFAULT_CENTER': (55.7558, 37.6173), 'DEFAULT_ZOOM': 12, } def mirrors_names(self, obj): return ", ".join(m.name for m in obj.mirrors.all()) mirrors_names.short_description = "Зеркала" def formatted_timestamp(self, obj): if not obj.timestamp: return "" local_time = timezone.localtime(obj.timestamp) return local_time.strftime("%d.%m.%Y %H:%M:%S") formatted_timestamp.short_description = "Дата и время" formatted_timestamp.admin_order_field = "timestamp" def geo_coords(self, obj): longitude = obj.coords.coords[0] latitude = obj.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}" geo_coords.short_description = "Координаты геолокации" def kupsat_coords(self, obj): if obj.coords_kupsat is None: return "-" longitude = obj.coords_kupsat.coords[0] latitude = obj.coords_kupsat.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}" kupsat_coords.short_description = "Координаты Кубсата" def valid_coords(self, obj): if obj.coords_valid is None: return "-" longitude = obj.coords_valid.coords[0] latitude = obj.coords_valid.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}" valid_coords.short_description = "Координаты оперативного отдела" def show_on_map(modeladmin, request, queryset): # Получаем список ID выбранных объектов selected_ids = queryset.values_list('id', flat=True) # Формируем строку вида "1,2,3" ids_str = ','.join(str(pk) for pk in selected_ids) # Перенаправляем на ваш кастомный view с картой return redirect(reverse('admin_show_map') + f'?ids={ids_str}') show_on_map.short_description = "Показать выбранные на карте" @admin.register(ObjItem) class ObjectAdmin(admin.ModelAdmin): list_display = ( "name", "sat_name", "freq", "freq_range", "pol", "bod_velocity", "modulation", "snr", "geo_coords", "kupsat_coords", "valid_coords", "distance_geo_kup", "distance_geo_valid", "distance_kup_valid", ) list_display_links = ("name",) list_filter = ( UniqueToggleFilter, ("id_vch_load__id_satellite", MultiSelectRelatedDropdownFilter), ("id_vch_load__frequency", NumericRangeFilterBuilder()), ("id_vch_load__freq_range", NumericRangeFilterBuilder()), ("id_vch_load__snr", NumericRangeFilterBuilder()), ("id_vch_load__modulation", MultiSelectRelatedDropdownFilter), ("id_vch_load__polarization", MultiSelectRelatedDropdownFilter), GeoKupDistanceFilter, GeoValidDistanceFilter ) search_fields = ( "name", "id_geo__coords", # "id_satellite__name", # "id_vch_load__frequency", ) ordering = ("name",) list_select_related = ( # "id_satellite", "id_vch_load", "id_vch_load__polarization", "id_vch_load__modulation", "id_vch_load__id_satellite", "id_geo", "id_source_type" ) autocomplete_fields = ("id_geo",) raw_id_fields = ("id_vch_load",) # dynamic_raw_id_fields = ("id_vch_load",) actions = [show_on_map] def sat_name(self, obj): return obj.id_vch_load.id_satellite sat_name.short_description = "Спутник" sat_name.admin_order_field = "id_vch_load__id_satellite__name" def freq(self, obj): par = obj.id_vch_load return par.frequency freq.short_description = "Частота, МГц" freq.admin_order_field = "id_vch_load__frequency" def distance_geo_kup(self, obj): par = obj.id_geo.distance_coords_kup if par is None: return "-" return round(par, 3) distance_geo_kup.short_description = "Гео-куб, км" def distance_geo_valid(self, obj): par = obj.id_geo.distance_coords_valid if par is None: return "-" return round(par, 3) distance_geo_valid.short_description = "Гео-опер, км" def distance_kup_valid(self, obj): par = obj.id_geo.distance_kup_valid if par is None: return "-" return round(par, 3) distance_kup_valid.short_description = "Куб-опер, км" def pol(self, obj): par = obj.id_vch_load.polarization return par.name pol.short_description = "Поляризация" def freq_range(self, obj): par = obj.id_vch_load return par.freq_range freq_range.short_description = "Полоса, МГц" freq_range.admin_order_field = "id_vch_load__freq_range" def bod_velocity(self, obj): par = obj.id_vch_load return par.bod_velocity bod_velocity.short_description = "Сим. v, БОД" def modulation(self, obj): par = obj.id_vch_load.modulation return par.name modulation.short_description = "Модуляция" def snr(self, obj): par = obj.id_vch_load return par.snr snr.short_description = "ОСШ" def geo_coords(self, obj): geo = obj.id_geo 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}" geo_coords.short_description = "Координаты геолокации" geo_coords.admin_order_filed = "id_geo__coords" def kupsat_coords(self, obj): obj = obj.id_geo if obj.coords_kupsat is None: return "-" longitude = obj.coords_kupsat.coords[0] latitude = obj.coords_kupsat.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}" kupsat_coords.short_description = "Координаты Кубсата" def valid_coords(self, obj): obj = obj.id_geo if obj.coords_valid is None: return "-" longitude = obj.coords_valid.coords[0] latitude = obj.coords_valid.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}" valid_coords.short_description = "Координаты оперативного отдела"