Переделки и улучшения

This commit is contained in:
2025-11-21 16:56:58 +03:00
parent 58838614a5
commit 0d239ef1de
11 changed files with 604 additions and 138 deletions

View File

@@ -8,7 +8,7 @@ from django.http import JsonResponse
from django.views.generic import ListView, View
from django.shortcuts import get_object_or_404
from mainapp.models import Source, ObjectMark, CustomUser
from mainapp.models import Source, ObjectMark, CustomUser, Satellite
class ObjectMarksListView(LoginRequiredMixin, ListView):
@@ -27,25 +27,35 @@ class ObjectMarksListView(LoginRequiredMixin, ListView):
def get_queryset(self):
"""Получить queryset с предзагруженными связанными данными"""
from django.db.models import Count, Max
from django.db.models import Count, Max, Min
# Проверяем, выбран ли спутник
satellite_id = self.request.GET.get('satellite_id')
if not satellite_id:
# Если спутник не выбран, возвращаем пустой queryset
return Source.objects.none()
queryset = Source.objects.prefetch_related(
'source_objitems',
'source_objitems__parameter_obj',
'source_objitems__parameter_obj__id_satellite',
'source_objitems__parameter_obj__polarization',
'source_objitems__parameter_obj__modulation',
Prefetch(
'marks',
queryset=ObjectMark.objects.select_related('created_by__user').order_by('-timestamp')
)
).annotate(
mark_count=Count('marks'),
last_mark_date=Max('marks__timestamp')
last_mark_date=Max('marks__timestamp'),
# Аннотации для сортировки по параметрам (берем минимальное значение из связанных объектов)
min_frequency=Min('source_objitems__parameter_obj__frequency'),
min_freq_range=Min('source_objitems__parameter_obj__freq_range'),
min_bod_velocity=Min('source_objitems__parameter_obj__bod_velocity')
)
# Фильтрация по спутникам (мультивыбор)
satellite_ids = self.request.GET.getlist('satellite_id')
if satellite_ids:
queryset = queryset.filter(source_objitems__parameter_obj__id_satellite_id__in=satellite_ids).distinct()
# Фильтрация по выбранному спутнику (обязательно)
queryset = queryset.filter(source_objitems__parameter_obj__id_satellite_id=satellite_id).distinct()
# Фильтрация по статусу (есть/нет отметок)
mark_status = self.request.GET.get('mark_status')
@@ -87,7 +97,16 @@ class ObjectMarksListView(LoginRequiredMixin, ListView):
# Сортировка
sort = self.request.GET.get('sort', '-id')
allowed_sorts = ['id', '-id', 'created_at', '-created_at', 'last_mark_date', '-last_mark_date', 'mark_count', '-mark_count']
allowed_sorts = [
'id', '-id',
'created_at', '-created_at',
'last_mark_date', '-last_mark_date',
'mark_count', '-mark_count',
'frequency', '-frequency',
'freq_range', '-freq_range',
'bod_velocity', '-bod_velocity'
]
if sort in allowed_sorts:
# Для сортировки по last_mark_date нужно обработать NULL значения
if 'last_mark_date' in sort:
@@ -96,6 +115,21 @@ class ObjectMarksListView(LoginRequiredMixin, ListView):
queryset = queryset.order_by(
Coalesce(F('last_mark_date'), F('created_at')).desc() if sort.startswith('-') else Coalesce(F('last_mark_date'), F('created_at')).asc()
)
# Сортировка по частоте
elif sort == 'frequency':
queryset = queryset.order_by('min_frequency')
elif sort == '-frequency':
queryset = queryset.order_by('-min_frequency')
# Сортировка по полосе
elif sort == 'freq_range':
queryset = queryset.order_by('min_freq_range')
elif sort == '-freq_range':
queryset = queryset.order_by('-min_freq_range')
# Сортировка по бодовой скорости
elif sort == 'bod_velocity':
queryset = queryset.order_by('min_bod_velocity')
elif sort == '-bod_velocity':
queryset = queryset.order_by('-min_bod_velocity')
else:
queryset = queryset.order_by(sort)
else:
@@ -106,14 +140,17 @@ class ObjectMarksListView(LoginRequiredMixin, ListView):
def get_context_data(self, **kwargs):
"""Добавить дополнительные данные в контекст"""
context = super().get_context_data(**kwargs)
from mainapp.models import Satellite
from mainapp.utils import parse_pagination_params
# Данные для фильтров - только спутники, у которых есть источники
# Все спутники для выбора
context['satellites'] = Satellite.objects.filter(
parameters__objitem__source__isnull=False
).distinct().order_by('name')
# Выбранный спутник
satellite_id = self.request.GET.get('satellite_id')
context['selected_satellite_id'] = int(satellite_id) if satellite_id and satellite_id.isdigit() else None
context['users'] = CustomUser.objects.select_related('user').filter(
marks_created__isnull=False
).distinct().order_by('user__username')
@@ -121,26 +158,56 @@ class ObjectMarksListView(LoginRequiredMixin, ListView):
# Параметры пагинации
page_number, items_per_page = parse_pagination_params(self.request, default_per_page=50)
context['items_per_page'] = items_per_page
context['available_items_per_page'] = [25, 50, 100, 200]
context['available_items_per_page'] = [25, 50, 100, 200, 500]
# Параметры поиска и сортировки
context['search_query'] = self.request.GET.get('search', '')
context['sort'] = self.request.GET.get('sort', '-id')
# Параметры фильтров для отображения в UI (мультивыбор)
context['selected_satellites'] = [int(x) for x in self.request.GET.getlist('satellite_id') if x.isdigit()]
# Параметры фильтров для отображения в UI
context['selected_users'] = [int(x) for x in self.request.GET.getlist('user_id') if x.isdigit()]
context['filter_mark_status'] = self.request.GET.get('mark_status', '')
context['filter_date_from'] = self.request.GET.get('date_from', '')
context['filter_date_to'] = self.request.GET.get('date_to', '')
# Добавить информацию о возможности редактирования для каждой отметки
# и получить имя первого объекта для каждого источника
# Полноэкранный режим
context['full_width_page'] = True
# Добавить информацию о параметрах для каждого источника
for source in context['sources']:
# Получить имя первого объекта
first_objitem = source.source_objitems.first()
source.objitem_name = first_objitem.name if first_objitem and first_objitem.name else '-'
# Получить первый объект для параметров (они должны быть одинаковыми)
first_objitem = source.source_objitems.select_related(
'parameter_obj',
'parameter_obj__polarization',
'parameter_obj__modulation'
).first()
if first_objitem:
source.objitem_name = first_objitem.name if first_objitem.name else '-'
# Получить параметры
if first_objitem.parameter_obj:
param = first_objitem.parameter_obj
source.frequency = param.frequency if param.frequency else '-'
source.freq_range = param.freq_range if param.freq_range else '-'
source.polarization = param.polarization.name if param.polarization else '-'
source.modulation = param.modulation.name if param.modulation else '-'
source.bod_velocity = param.bod_velocity if param.bod_velocity else '-'
else:
source.frequency = '-'
source.freq_range = '-'
source.polarization = '-'
source.modulation = '-'
source.bod_velocity = '-'
else:
source.objitem_name = '-'
source.frequency = '-'
source.freq_range = '-'
source.polarization = '-'
source.modulation = '-'
source.bod_velocity = '-'
# Проверка возможности редактирования отметок
for mark in source.marks.all():
mark.editable = mark.can_edit()
@@ -187,6 +254,10 @@ class AddObjectMarkView(LoginRequiredMixin, View):
created_by=custom_user
)
# Обновляем дату последнего сигнала источника
source.update_last_signal_at()
source.save()
return JsonResponse({
'success': True,
'mark': {
@@ -225,6 +296,10 @@ class UpdateObjectMarkView(LoginRequiredMixin, View):
object_mark.mark = new_mark_value
object_mark.save()
# Обновляем дату последнего сигнала источника
object_mark.source.update_last_signal_at()
object_mark.source.save()
return JsonResponse({
'success': True,
'mark': {