Files
dbstorage/dbapp/mainapp/admin.py

602 lines
20 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 leaflet.forms.widgets import LeafletWidget
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 GeoInline(admin.StackedInline):
model = Geo
extra = 0
verbose_name = "Гео"
verbose_name_plural = "Гео"
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"),
}),
)
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 SourceTypeAdmin(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",)
filter_horizontal = ('objitems',) # For many-to-many relationship
# 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 = "Показать выбранные на карте"
class ObjItemForm(forms.ModelForm):
parameter = forms.ModelChoiceField(
queryset=Parameter.objects.all(),
required=False,
label="Параметр"
)
class Meta:
model = ObjItem
fields = '__all__'
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Set initial value if the ObjItem already has a parameter
if self.instance.pk:
first_param = self.instance.parameters_obj.first()
if first_param:
self.fields['parameter'].initial = first_param
def save(self, commit=True):
instance = super().save(commit=commit)
# Handle the single parameter assignment - replace all existing relationships
if self.cleaned_data.get('parameter'):
# Clear all existing parameter relationships
instance.parameters_obj.clear()
# Add the selected parameter
instance.parameters_obj.add(self.cleaned_data['parameter'])
else:
# If no parameter selected, clear all
instance.parameters_obj.clear()
return instance
@admin.register(ObjItem)
class ObjectAdmin(admin.ModelAdmin):
form = ObjItemForm
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,
("parameters_obj__id_satellite", MultiSelectRelatedDropdownFilter),
("parameters_obj__frequency", NumericRangeFilterBuilder()),
("parameters_obj__freq_range", NumericRangeFilterBuilder()),
("parameters_obj__snr", NumericRangeFilterBuilder()),
("parameters_obj__modulation", MultiSelectRelatedDropdownFilter),
("parameters_obj__polarization", MultiSelectRelatedDropdownFilter),
GeoKupDistanceFilter,
GeoValidDistanceFilter
)
search_fields = (
"name",
"geo_obj__coords",
"parameters_obj__frequency",
)
ordering = ("name",)
inlines = [GeoInline]
actions = [show_on_map]
def get_queryset(self, request):
qs = super().get_queryset(request)
return qs.select_related('geo_obj').prefetch_related(
'parameters_obj__id_satellite',
'parameters_obj__polarization',
'parameters_obj__modulation',
'parameters_obj__standard'
)
def sat_name(self, obj):
param = next(iter(obj.parameters_obj.all()), None)
if param and param.id_satellite:
return param.id_satellite.name
return "-"
sat_name.short_description = "Спутник"
sat_name.admin_order_field = "parameters_obj__id_satellite__name"
def freq(self, obj):
# param = obj.parameters_obj.first()
param = next(iter(obj.parameters_obj.all()), None)
if param:
return param.frequency
return "-"
freq.short_description = "Частота, МГц"
freq.admin_order_field = "parameters_obj__frequency"
def distance_geo_kup(self, obj):
geo = obj.geo_obj
if not geo or geo.distance_coords_kup is None:
return "-"
return round(geo.distance_coords_kup, 3)
distance_geo_kup.short_description = "Гео-куб, км"
def distance_geo_valid(self, obj):
geo = obj.geo_obj
if not geo or geo.distance_coords_valid is None:
return "-"
return round(geo.distance_coords_valid, 3)
distance_geo_valid.short_description = "Гео-опер, км"
def distance_kup_valid(self, obj):
geo = obj.geo_obj
if not geo or geo.distance_kup_valid is None:
return "-"
return round(geo.distance_kup_valid, 3)
distance_kup_valid.short_description = "Куб-опер, км"
def pol(self, obj):
# Get the first parameter associated with this objitem to display polarization
param = next(iter(obj.parameters_obj.all()), None)
if param and param.polarization:
return param.polarization.name
return "-"
pol.short_description = "Поляризация"
def freq_range(self, obj):
# Get the first parameter associated with this objitem to display freq_range
param = next(iter(obj.parameters_obj.all()), None)
if param:
return param.freq_range
return "-"
freq_range.short_description = "Полоса, МГц"
freq_range.admin_order_field = "parameters_obj__freq_range"
def bod_velocity(self, obj):
# Get the first parameter associated with this objitem to display bod_velocity
param = next(iter(obj.parameters_obj.all()), None)
if param:
return param.bod_velocity
return "-"
bod_velocity.short_description = "Сим. v, БОД"
def modulation(self, obj):
# Get the first parameter associated with this objitem to display modulation
param = next(iter(obj.parameters_obj.all()), None)
if param and param.modulation:
return param.modulation.name
return "-"
modulation.short_description = "Модуляция"
def snr(self, obj):
# Get the first parameter associated with this objitem to display snr
param = next(iter(obj.parameters_obj.all()), None)
if param:
return param.snr
return "-"
snr.short_description = "ОСШ"
def geo_coords(self, obj):
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}"
geo_coords.short_description = "Координаты геолокации"
geo_coords.admin_order_field = "geo_obj__coords"
def kupsat_coords(self, obj):
geo = obj.geo_obj
if not geo or not geo.coords_kupsat:
return "-"
longitude = geo.coords_kupsat.coords[0]
latitude = geo.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):
geo = obj.geo_obj
if not geo or not geo.coords_valid:
return "-"
longitude = geo.coords_valid.coords[0]
latitude = geo.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 = "Координаты оперативного отдела"