Правки и улучшения визуала. Добавил функционал отметок.
This commit is contained in:
@@ -1,10 +1,491 @@
|
||||
"""
|
||||
Base views and utilities.
|
||||
"""
|
||||
from datetime import datetime, timedelta
|
||||
from django.contrib.auth import logout
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.core.paginator import Paginator
|
||||
from django.db.models import Count, Q
|
||||
from django.shortcuts import redirect, render
|
||||
from django.views import View
|
||||
|
||||
from ..models import Source, ObjItem, Satellite, Modulation, Polarization, ObjectMark
|
||||
from ..utils import parse_pagination_params
|
||||
|
||||
|
||||
class HomeView(LoginRequiredMixin, View):
|
||||
"""
|
||||
Main page with filters for displaying sources or objitems.
|
||||
"""
|
||||
|
||||
def get(self, request):
|
||||
# Get pagination parameters
|
||||
page_number, items_per_page = parse_pagination_params(request)
|
||||
|
||||
# Get display mode: 'sources' or 'objitems'
|
||||
display_mode = request.GET.get("display_mode", "sources")
|
||||
|
||||
# Get filter parameters
|
||||
selected_satellites = request.GET.getlist("satellite_id")
|
||||
date_from = request.GET.get("date_from", "").strip()
|
||||
date_to = request.GET.get("date_to", "").strip()
|
||||
freq_min = request.GET.get("freq_min", "").strip()
|
||||
freq_max = request.GET.get("freq_max", "").strip()
|
||||
range_min = request.GET.get("range_min", "").strip()
|
||||
range_max = request.GET.get("range_max", "").strip()
|
||||
selected_modulations = request.GET.getlist("modulation")
|
||||
selected_polarizations = request.GET.getlist("polarization")
|
||||
|
||||
# Source-specific filters
|
||||
has_coords_average = request.GET.get("has_coords_average")
|
||||
has_kupsat = request.GET.get("has_kupsat")
|
||||
has_valid = request.GET.get("has_valid")
|
||||
has_reference = request.GET.get("has_reference")
|
||||
|
||||
# ObjItem-specific filters
|
||||
has_geo = request.GET.get("has_geo")
|
||||
has_lyngsat = request.GET.get("has_lyngsat")
|
||||
|
||||
# Marks filters
|
||||
show_marks = request.GET.get("show_marks", "0")
|
||||
marks_date_from = request.GET.get("marks_date_from", "").strip()
|
||||
marks_date_to = request.GET.get("marks_date_to", "").strip()
|
||||
marks_status = request.GET.get("marks_status", "") # all, present, absent
|
||||
|
||||
# Get all satellites, modulations, polarizations for filters
|
||||
satellites = Satellite.objects.all().order_by("name")
|
||||
modulations = Modulation.objects.all().order_by("name")
|
||||
polarizations = Polarization.objects.all().order_by("name")
|
||||
|
||||
# Prepare context
|
||||
context = {
|
||||
'display_mode': display_mode,
|
||||
'satellites': satellites,
|
||||
'modulations': modulations,
|
||||
'polarizations': polarizations,
|
||||
'selected_satellites': [int(x) for x in selected_satellites if x.isdigit()],
|
||||
'selected_modulations': [int(x) for x in selected_modulations if x.isdigit()],
|
||||
'selected_polarizations': [int(x) for x in selected_polarizations if x.isdigit()],
|
||||
'date_from': date_from,
|
||||
'date_to': date_to,
|
||||
'freq_min': freq_min,
|
||||
'freq_max': freq_max,
|
||||
'range_min': range_min,
|
||||
'range_max': range_max,
|
||||
'has_coords_average': has_coords_average,
|
||||
'has_kupsat': has_kupsat,
|
||||
'has_valid': has_valid,
|
||||
'has_reference': has_reference,
|
||||
'has_geo': has_geo,
|
||||
'has_lyngsat': has_lyngsat,
|
||||
'show_marks': show_marks,
|
||||
'marks_date_from': marks_date_from,
|
||||
'marks_date_to': marks_date_to,
|
||||
'marks_status': marks_status,
|
||||
'items_per_page': items_per_page,
|
||||
'available_items_per_page': [50, 100, 500, 1000],
|
||||
'full_width_page': True,
|
||||
}
|
||||
|
||||
if display_mode == "objitems":
|
||||
# Display ObjItems
|
||||
queryset = self._get_objitems_queryset(
|
||||
selected_satellites, date_from, date_to,
|
||||
freq_min, freq_max, range_min, range_max,
|
||||
selected_modulations, selected_polarizations,
|
||||
has_geo, has_lyngsat
|
||||
)
|
||||
|
||||
paginator = Paginator(queryset, items_per_page)
|
||||
page_obj = paginator.get_page(page_number)
|
||||
|
||||
processed_objitems = self._process_objitems(
|
||||
page_obj, show_marks, marks_date_from, marks_date_to, marks_status
|
||||
)
|
||||
|
||||
context.update({
|
||||
'page_obj': page_obj,
|
||||
'processed_objitems': processed_objitems,
|
||||
})
|
||||
else:
|
||||
# Display Sources
|
||||
queryset = self._get_sources_queryset(
|
||||
selected_satellites, date_from, date_to,
|
||||
freq_min, freq_max, range_min, range_max,
|
||||
selected_modulations, selected_polarizations,
|
||||
has_coords_average, has_kupsat, has_valid, has_reference
|
||||
)
|
||||
|
||||
paginator = Paginator(queryset, items_per_page)
|
||||
page_obj = paginator.get_page(page_number)
|
||||
|
||||
processed_sources = self._process_sources(
|
||||
page_obj, show_marks, marks_date_from, marks_date_to, marks_status
|
||||
)
|
||||
|
||||
context.update({
|
||||
'page_obj': page_obj,
|
||||
'processed_sources': processed_sources,
|
||||
})
|
||||
|
||||
return render(request, "mainapp/home.html", context)
|
||||
|
||||
def _get_sources_queryset(self, selected_satellites, date_from, date_to,
|
||||
freq_min, freq_max, range_min, range_max,
|
||||
selected_modulations, selected_polarizations,
|
||||
has_coords_average, has_kupsat, has_valid, has_reference):
|
||||
"""Build queryset for sources with filters."""
|
||||
sources = Source.objects.prefetch_related(
|
||||
'source_objitems',
|
||||
'source_objitems__parameter_obj',
|
||||
'source_objitems__parameter_obj__id_satellite',
|
||||
'source_objitems__geo_obj'
|
||||
).annotate(objitem_count=Count('source_objitems'))
|
||||
|
||||
# Filter by satellites
|
||||
if selected_satellites:
|
||||
sources = sources.filter(
|
||||
source_objitems__parameter_obj__id_satellite_id__in=selected_satellites
|
||||
).distinct()
|
||||
|
||||
# Filter by date range (using Geo timestamps)
|
||||
if date_from or date_to:
|
||||
geo_filter = Q()
|
||||
if date_from:
|
||||
try:
|
||||
date_from_obj = datetime.strptime(date_from, "%Y-%m-%d")
|
||||
geo_filter &= Q(source_objitems__geo_obj__timestamp__gte=date_from_obj)
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
if date_to:
|
||||
try:
|
||||
date_to_obj = datetime.strptime(date_to, "%Y-%m-%d") + timedelta(days=1)
|
||||
geo_filter &= Q(source_objitems__geo_obj__timestamp__lt=date_to_obj)
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
if geo_filter:
|
||||
sources = sources.filter(geo_filter).distinct()
|
||||
|
||||
# Filter by frequency
|
||||
if freq_min:
|
||||
try:
|
||||
sources = sources.filter(
|
||||
source_objitems__parameter_obj__frequency__gte=float(freq_min)
|
||||
).distinct()
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
if freq_max:
|
||||
try:
|
||||
sources = sources.filter(
|
||||
source_objitems__parameter_obj__frequency__lte=float(freq_max)
|
||||
).distinct()
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
# Filter by frequency range
|
||||
if range_min:
|
||||
try:
|
||||
sources = sources.filter(
|
||||
source_objitems__parameter_obj__freq_range__gte=float(range_min)
|
||||
).distinct()
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
if range_max:
|
||||
try:
|
||||
sources = sources.filter(
|
||||
source_objitems__parameter_obj__freq_range__lte=float(range_max)
|
||||
).distinct()
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
# Filter by modulation
|
||||
if selected_modulations:
|
||||
sources = sources.filter(
|
||||
source_objitems__parameter_obj__modulation_id__in=selected_modulations
|
||||
).distinct()
|
||||
|
||||
# Filter by polarization
|
||||
if selected_polarizations:
|
||||
sources = sources.filter(
|
||||
source_objitems__parameter_obj__polarization_id__in=selected_polarizations
|
||||
).distinct()
|
||||
|
||||
# Filter by coordinates presence
|
||||
if has_coords_average == "1":
|
||||
sources = sources.filter(coords_average__isnull=False)
|
||||
elif has_coords_average == "0":
|
||||
sources = sources.filter(coords_average__isnull=True)
|
||||
|
||||
if has_kupsat == "1":
|
||||
sources = sources.filter(coords_kupsat__isnull=False)
|
||||
elif has_kupsat == "0":
|
||||
sources = sources.filter(coords_kupsat__isnull=True)
|
||||
|
||||
if has_valid == "1":
|
||||
sources = sources.filter(coords_valid__isnull=False)
|
||||
elif has_valid == "0":
|
||||
sources = sources.filter(coords_valid__isnull=True)
|
||||
|
||||
if has_reference == "1":
|
||||
sources = sources.filter(coords_reference__isnull=False)
|
||||
elif has_reference == "0":
|
||||
sources = sources.filter(coords_reference__isnull=True)
|
||||
|
||||
return sources.order_by('-id')
|
||||
|
||||
def _get_objitems_queryset(self, selected_satellites, date_from, date_to,
|
||||
freq_min, freq_max, range_min, range_max,
|
||||
selected_modulations, selected_polarizations,
|
||||
has_geo, has_lyngsat):
|
||||
"""Build queryset for objitems with filters."""
|
||||
objitems = ObjItem.objects.select_related(
|
||||
'parameter_obj',
|
||||
'parameter_obj__id_satellite',
|
||||
'parameter_obj__modulation',
|
||||
'parameter_obj__polarization',
|
||||
'geo_obj',
|
||||
'source',
|
||||
'lyngsat_source'
|
||||
)
|
||||
|
||||
# Filter by satellites
|
||||
if selected_satellites:
|
||||
objitems = objitems.filter(parameter_obj__id_satellite_id__in=selected_satellites)
|
||||
|
||||
# Filter by date range
|
||||
if date_from:
|
||||
try:
|
||||
date_from_obj = datetime.strptime(date_from, "%Y-%m-%d")
|
||||
objitems = objitems.filter(geo_obj__timestamp__gte=date_from_obj)
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
if date_to:
|
||||
try:
|
||||
date_to_obj = datetime.strptime(date_to, "%Y-%m-%d") + timedelta(days=1)
|
||||
objitems = objitems.filter(geo_obj__timestamp__lt=date_to_obj)
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
# Filter by frequency
|
||||
if freq_min:
|
||||
try:
|
||||
objitems = objitems.filter(parameter_obj__frequency__gte=float(freq_min))
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
if freq_max:
|
||||
try:
|
||||
objitems = objitems.filter(parameter_obj__frequency__lte=float(freq_max))
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
# Filter by frequency range
|
||||
if range_min:
|
||||
try:
|
||||
objitems = objitems.filter(parameter_obj__freq_range__gte=float(range_min))
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
if range_max:
|
||||
try:
|
||||
objitems = objitems.filter(parameter_obj__freq_range__lte=float(range_max))
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
# Filter by modulation
|
||||
if selected_modulations:
|
||||
objitems = objitems.filter(parameter_obj__modulation_id__in=selected_modulations)
|
||||
|
||||
# Filter by polarization
|
||||
if selected_polarizations:
|
||||
objitems = objitems.filter(parameter_obj__polarization_id__in=selected_polarizations)
|
||||
|
||||
# Filter by coordinates presence
|
||||
if has_geo == "1":
|
||||
objitems = objitems.filter(geo_obj__isnull=False)
|
||||
elif has_geo == "0":
|
||||
objitems = objitems.filter(geo_obj__isnull=True)
|
||||
|
||||
# Filter by LyngSat connection
|
||||
if has_lyngsat == "1":
|
||||
objitems = objitems.filter(lyngsat_source__isnull=False)
|
||||
elif has_lyngsat == "0":
|
||||
objitems = objitems.filter(lyngsat_source__isnull=True)
|
||||
|
||||
return objitems.order_by('-id')
|
||||
|
||||
def _process_sources(self, page_obj, show_marks="0", marks_date_from="", marks_date_to="", marks_status=""):
|
||||
"""Process sources for display."""
|
||||
processed = []
|
||||
|
||||
for source in page_obj:
|
||||
# Get satellites
|
||||
satellite_names = set()
|
||||
for objitem in source.source_objitems.all():
|
||||
if objitem.parameter_obj and objitem.parameter_obj.id_satellite:
|
||||
satellite_names.add(objitem.parameter_obj.id_satellite.name)
|
||||
|
||||
# Format coordinates
|
||||
def format_coords(point):
|
||||
if point:
|
||||
lon, lat = point.coords[0], point.coords[1]
|
||||
lon_str = f"{lon}E" if lon > 0 else f"{abs(lon)}W"
|
||||
lat_str = f"{lat}N" if lat > 0 else f"{abs(lat)}S"
|
||||
return f"{lat_str} {lon_str}"
|
||||
return "-"
|
||||
|
||||
# Get marks if requested
|
||||
marks_data = []
|
||||
if show_marks == "1":
|
||||
marks_qs = source.marks.select_related('created_by__user').all()
|
||||
|
||||
# Filter marks by date
|
||||
if marks_date_from:
|
||||
try:
|
||||
date_from_obj = datetime.strptime(marks_date_from, "%Y-%m-%dT%H:%M")
|
||||
marks_qs = marks_qs.filter(timestamp__gte=date_from_obj)
|
||||
except (ValueError, TypeError):
|
||||
try:
|
||||
date_from_obj = datetime.strptime(marks_date_from, "%Y-%m-%d")
|
||||
marks_qs = marks_qs.filter(timestamp__gte=date_from_obj)
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
if marks_date_to:
|
||||
try:
|
||||
date_to_obj = datetime.strptime(marks_date_to, "%Y-%m-%dT%H:%M")
|
||||
marks_qs = marks_qs.filter(timestamp__lte=date_to_obj)
|
||||
except (ValueError, TypeError):
|
||||
try:
|
||||
date_to_obj = datetime.strptime(marks_date_to, "%Y-%m-%d") + timedelta(days=1)
|
||||
marks_qs = marks_qs.filter(timestamp__lt=date_to_obj)
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
# Filter marks by status
|
||||
if marks_status == "present":
|
||||
marks_qs = marks_qs.filter(mark=True)
|
||||
elif marks_status == "absent":
|
||||
marks_qs = marks_qs.filter(mark=False)
|
||||
|
||||
# Process marks
|
||||
for mark in marks_qs:
|
||||
marks_data.append({
|
||||
'id': mark.id,
|
||||
'mark': mark.mark,
|
||||
'timestamp': mark.timestamp,
|
||||
'created_by': str(mark.created_by) if mark.created_by else "-",
|
||||
'can_edit': mark.can_edit(),
|
||||
})
|
||||
|
||||
processed.append({
|
||||
'id': source.id,
|
||||
'satellites': ", ".join(sorted(satellite_names)) if satellite_names else "-",
|
||||
'objitem_count': source.objitem_count,
|
||||
'coords_average': format_coords(source.coords_average),
|
||||
'coords_kupsat': format_coords(source.coords_kupsat),
|
||||
'coords_valid': format_coords(source.coords_valid),
|
||||
'coords_reference': format_coords(source.coords_reference),
|
||||
'created_at': source.created_at,
|
||||
'marks': marks_data,
|
||||
})
|
||||
|
||||
return processed
|
||||
|
||||
def _process_objitems(self, page_obj, show_marks="0", marks_date_from="", marks_date_to="", marks_status=""):
|
||||
"""Process objitems for display."""
|
||||
processed = []
|
||||
|
||||
for objitem in page_obj:
|
||||
param = objitem.parameter_obj
|
||||
geo = objitem.geo_obj
|
||||
source = objitem.source
|
||||
|
||||
# Format geo coordinates
|
||||
geo_coords = "-"
|
||||
geo_date = "-"
|
||||
if geo and geo.coords:
|
||||
lon, lat = geo.coords.coords[0], geo.coords.coords[1]
|
||||
lon_str = f"{lon}E" if lon > 0 else f"{abs(lon)}W"
|
||||
lat_str = f"{lat}N" if lat > 0 else f"{abs(lat)}S"
|
||||
geo_coords = f"{lat_str} {lon_str}"
|
||||
if geo.timestamp:
|
||||
geo_date = geo.timestamp.strftime("%Y-%m-%d")
|
||||
|
||||
# Format source coordinates
|
||||
def format_coords(point):
|
||||
if point:
|
||||
lon, lat = point.coords[0], point.coords[1]
|
||||
lon_str = f"{lon}E" if lon > 0 else f"{abs(lon)}W"
|
||||
lat_str = f"{lat}N" if lat > 0 else f"{abs(lat)}S"
|
||||
return f"{lat_str} {lon_str}"
|
||||
return "-"
|
||||
|
||||
kupsat_coords = format_coords(source.coords_kupsat) if source else "-"
|
||||
valid_coords = format_coords(source.coords_valid) if source else "-"
|
||||
|
||||
# Get marks if requested
|
||||
marks_data = []
|
||||
if show_marks == "1":
|
||||
marks_qs = objitem.marks.select_related('created_by__user').all()
|
||||
|
||||
# Filter marks by date
|
||||
if marks_date_from:
|
||||
try:
|
||||
date_from_obj = datetime.strptime(marks_date_from, "%Y-%m-%d")
|
||||
marks_qs = marks_qs.filter(timestamp__gte=date_from_obj)
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
if marks_date_to:
|
||||
try:
|
||||
date_to_obj = datetime.strptime(marks_date_to, "%Y-%m-%d") + timedelta(days=1)
|
||||
marks_qs = marks_qs.filter(timestamp__lt=date_to_obj)
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
# Filter marks by status
|
||||
if marks_status == "present":
|
||||
marks_qs = marks_qs.filter(mark=True)
|
||||
elif marks_status == "absent":
|
||||
marks_qs = marks_qs.filter(mark=False)
|
||||
|
||||
# Process marks
|
||||
for mark in marks_qs:
|
||||
marks_data.append({
|
||||
'id': mark.id,
|
||||
'mark': mark.mark,
|
||||
'timestamp': mark.timestamp,
|
||||
'created_by': str(mark.created_by) if mark.created_by else "-",
|
||||
'can_edit': mark.can_edit(),
|
||||
})
|
||||
|
||||
processed.append({
|
||||
'id': objitem.id,
|
||||
'name': objitem.name or "-",
|
||||
'satellite': param.id_satellite.name if param and param.id_satellite else "-",
|
||||
'frequency': param.frequency if param else "-",
|
||||
'freq_range': param.freq_range if param else "-",
|
||||
'polarization': param.polarization.name if param and param.polarization else "-",
|
||||
'modulation': param.modulation.name if param and param.modulation else "-",
|
||||
'bod_velocity': param.bod_velocity if param else "-",
|
||||
'snr': param.snr if param else "-",
|
||||
'geo_coords': geo_coords,
|
||||
'geo_date': geo_date,
|
||||
'kupsat_coords': kupsat_coords,
|
||||
'valid_coords': valid_coords,
|
||||
'source_id': source.id if source else None,
|
||||
'lyngsat_id': objitem.lyngsat_source.id if objitem.lyngsat_source else None,
|
||||
'marks': marks_data,
|
||||
})
|
||||
|
||||
return processed
|
||||
|
||||
|
||||
class ActionsPageView(View):
|
||||
"""View for displaying the actions page."""
|
||||
|
||||
Reference in New Issue
Block a user