This commit is contained in:
2025-10-24 16:54:20 +03:00
parent 5e40201460
commit 178854c6ba
15 changed files with 505 additions and 232 deletions

2
.gitignore vendored
View File

@@ -10,6 +10,8 @@ wheels/
.venv .venv
.hintrc .hintrc
.vscode .vscode
data.json
.env
django-leaflet django-leaflet
admin-interface admin-interface

29
dbapp/.dockerignore Normal file
View File

@@ -0,0 +1,29 @@
__pycache__
*.pyc
*.pyo
*.pyd
.Python
.pytest_cache
.coverage
.git
.gitignore
README.md
.env
.DS_Store
.settings
.vscode
.idea
*.swp
*.swo
*~
__pycache__/
*.so
.Python
.coverage
.pytest_cache
.venv
venv/
env/
.pyre/
node_modules/
.DS_Store

10
dbapp/.env.example Normal file
View File

@@ -0,0 +1,10 @@
# Production environment variables
DEBUG=False
ENVIRONMENT=production
SECRET_KEY=your_very_long_secret_key_here_change_this_to_something_secure
DB_NAME=geodb
DB_USER=geralt
DB_PASSWORD=your_secure_db_password
DB_HOST=db
DB_PORT=5432
ALLOWED_HOSTS=localhost,yourdomain.com

51
dbapp/Dockerfile Normal file
View File

@@ -0,0 +1,51 @@
# Use Python 3.13 slim image as base
FROM python:3.13.9-slim
# Set environment variables
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PYTHONPATH=/app \
DJANGO_SETTINGS_MODULE=dbapp.settings.production
# Install system dependencies including GDAL and PostGIS dependencies
RUN apt-get update && apt-get install -y \
gdal-bin \
libgdal-dev \
proj-bin \
proj-data \
libproj-dev \
libgeos-dev \
postgresql-client \
build-essential \
libpq-dev \
gcc \
g++ \
&& rm -rf /var/lib/apt/lists/*
# Install Python dependencies for GDAL
RUN pip install --upgrade pip && \
pip install --no-cache-dir GDAL==$(gdal-config --version)
# Set work directory
WORKDIR /app
# Copy project requirements
COPY pyproject.toml uv.lock ./
# Install uv package manager
RUN pip install --upgrade pip && pip install uv
# Install dependencies using uv
RUN uv pip install --system --no-cache-dir -r uv.lock
# Copy project
COPY . .
# Collect static files
RUN python manage.py collectstatic --noinput
# Expose port
EXPOSE 8000
# Run gunicorn server
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "3", "dbapp.wsgi:application"]

73
dbapp/Dockerfile.prod Normal file
View File

@@ -0,0 +1,73 @@
# Multi-stage build for production
FROM python:3.13-slim as requirements-stage
# Install system dependencies
RUN apt-get update && apt-get install -y \
gdal-bin \
libgdal-dev \
proj-bin \
proj-data \
libproj-dev \
libgeos-dev \
build-essential \
libpq-dev \
gcc \
g++ \
&& rm -rf /var/lib/apt/lists/*
# Install Python dependencies for GDAL
RUN pip install --upgrade pip && \
pip install --no-cache-dir GDAL==$(gdal-config --version)
WORKDIR /app
# Copy project requirements
COPY pyproject.toml uv.lock ./
# Install uv package manager
RUN pip install --upgrade pip && pip install uv
# Install dependencies using uv
RUN uv pip install --system --only-binary=gdal,shapely,pyproj --no-cache-dir -r uv.lock
# Production stage
FROM python:3.13-slim
# Install runtime system dependencies
RUN apt-get update && apt-get install -y \
gdal-bin \
libgdal30 \
libproj25 \
libgeos-c1v5 \
postgresql-client \
libpq5 \
&& rm -rf /var/lib/apt/lists/*
# Set environment variables
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
DJANGO_SETTINGS_MODULE=dbapp.settings.production
# Set work directory
WORKDIR /app
# Copy Python dependencies from previous stage
COPY --from=requirements-stage /usr/local/lib/python3.13/site-packages /usr/local/lib/python3.13/site-packages
COPY --from=requirements-stage /usr/local/bin /usr/local/bin
# Copy project
COPY . .
# Create non-root user for security
RUN useradd --create-home --shell /bin/bash app && chown -R app:app /app
USER app
# Collect static files
RUN python manage.py collectstatic --noinput
# Expose port
EXPOSE 8000
# Run gunicorn server
CMD ["gunicorn", "--bind", "0.0.0.0:8000", "--workers", "3", "--timeout", "120", "dbapp.wsgi:application"]

View File

@@ -0,0 +1,13 @@
import os
from dotenv import load_dotenv
# Load environment variables
load_dotenv()
# Determine the environment and import the appropriate settings
ENVIRONMENT = os.getenv('ENVIRONMENT', 'development')
if ENVIRONMENT == 'production':
from .production import *
else:
from .development import *

View File

@@ -12,6 +12,10 @@ https://docs.djangoproject.com/en/5.2/ref/settings/
from pathlib import Path from pathlib import Path
import os import os
from dotenv import load_dotenv
# Load environment variables from .env file
load_dotenv()
if os.name == 'nt': if os.name == 'nt':
OSGEO4W = r"C:\Program Files\OSGeo4W" OSGEO4W = r"C:\Program Files\OSGeo4W"
@@ -29,18 +33,17 @@ BASE_DIR = Path(__file__).resolve().parent.parent
# See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/ # See https://docs.djangoproject.com/en/5.2/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret! # SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'django-insecure-7etj5f7buo2a57xv=w3^&llusq8rii7b_gd)9$t_1xcnao!^tq' SECRET_KEY = os.getenv('SECRET_KEY', 'django-insecure-7etj5f7buo2a57xv=w3^&llusq8rii7b_gd)9$t_1xcnao!^tq')
# SECURITY WARNING: don't run with debug turned on in production! # SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True DEBUG = os.getenv('DEBUG', 'True').lower() == 'true'
ALLOWED_HOSTS = ['*'] ALLOWED_HOSTS = os.getenv('ALLOWED_HOSTS', 'localhost,127.0.0.1').split(',')
# Application definition # Application definition
INSTALLED_APPS = [ INSTALLED_APPS = [
# 'django_daisy',
'dal', 'dal',
'dal_select2', 'dal_select2',
"admin_interface", "admin_interface",
@@ -64,6 +67,9 @@ INSTALLED_APPS = [
'debug_toolbar' 'debug_toolbar'
] ]
# Note: Custom user model is implemented via OneToOneField relationship
# AUTH_USER_MODEL = 'mainapp.CustomUser'
MIDDLEWARE = [ MIDDLEWARE = [
"debug_toolbar.middleware.DebugToolbarMiddleware", #Добавил "debug_toolbar.middleware.DebugToolbarMiddleware", #Добавил
'django.middleware.security.SecurityMiddleware', 'django.middleware.security.SecurityMiddleware',
@@ -81,7 +87,9 @@ ROOT_URLCONF = 'dbapp.urls'
TEMPLATES = [ TEMPLATES = [
{ {
'BACKEND': 'django.template.backends.django.DjangoTemplates', 'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [], 'DIRS': [
BASE_DIR / 'templates', # Main project templates directory
],
'APP_DIRS': True, 'APP_DIRS': True,
'OPTIONS': { 'OPTIONS': {
'context_processors': [ 'context_processors': [
@@ -101,12 +109,12 @@ WSGI_APPLICATION = 'dbapp.wsgi.application'
DATABASES = { DATABASES = {
'default': { 'default': {
'ENGINE': 'django.contrib.gis.db.backends.postgis', 'ENGINE': os.getenv('DB_ENGINE', 'django.contrib.gis.db.backends.postgis'),
'NAME': 'geodb', 'NAME': os.getenv('DB_NAME', 'db'),
'USER': 'geralt', 'USER': os.getenv('DB_USER', 'user'),
'PASSWORD': '27082025STC', 'PASSWORD': os.getenv('DB_PASSWORD', 'password'),
'HOST': 'localhost', 'HOST': os.getenv('DB_HOST', 'localhost'),
'PORT': '5432', 'PORT': os.getenv('DB_PORT', '5432'),
} }
} }
@@ -147,7 +155,7 @@ USE_TZ = True
STATIC_URL = '/static/' STATIC_URL = '/static/'
STATICFILES_DIRS = [ STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static'), BASE_DIR.parent / 'static', # Reference to the static directory at project root
] ]
# Default primary key field type # Default primary key field type

View File

@@ -0,0 +1,9 @@
from .base import *
# Development-specific settings
DEBUG = True
# Allow all hosts in development
ALLOWED_HOSTS = ['*']
# Additional development settings can go here

View File

@@ -0,0 +1,48 @@
from .base import *
import os
from dotenv import load_dotenv
# Production-specific settings
DEBUG = False
TEMPLATE_DEBUG = DEBUG
# In production, specify allowed hosts explicitly
ALLOWED_HOSTS = os.getenv('ALLOWED_HOSTS_PROD', 'localhost,127.0.0.1').split(',')
# Security settings for production
SECURE_BROWSER_XSS_FILTER = True
SECURE_CONTENT_TYPE_NOSNIFF = True
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_SECONDS = 31536000
SECURE_REDIRECT_EXEMPT = []
SECURE_SSL_REDIRECT = True
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
# Template caching for production
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
BASE_DIR / 'templates', # Main project templates directory
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
'loaders': [
('django.template.loaders.cached.Loader', [
'django.template.loaders.filesystem.Loader',
'django.template.loaders.app_directories.Loader',
]),
],
},
},
]
# Static files settings for production
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.ManifestStaticFilesStorage'

View File

@@ -5,16 +5,16 @@ from . import views
urlpatterns = [ urlpatterns = [
path('', views.home_page, name='home'), path('', views.HomePageView.as_view(), name='home'),
path('excel-data', views.load_excel_data, name='load_excel_data'), path('excel-data', views.LoadExcelDataView.as_view(), name='load_excel_data'),
path('satellites', views.add_satellites, name='add_sats'), path('satellites', views.AddSatellitesView.as_view(), name='add_sats'),
path('api/locations/<int:sat_id>/geojson/', views.get_locations, name='locations_by_id'), path('api/locations/<int:sat_id>/geojson/', views.GetLocationsView.as_view(), name='locations_by_id'),
path('transponders', views.add_transponders, name='add_trans'), path('transponders', views.AddTranspondersView.as_view(), name='add_trans'),
path('csv-data', views.load_raw_csv_data, name='load_csv_data'), path('csv-data', views.LoadCsvDataView.as_view(), name='load_csv_data'),
path('map-points/', views.show_map_view, name='admin_show_map'), path('map-points/', views.ShowMapView.as_view(), name='admin_show_map'),
path('cluster/', views.cluster_test, name='cluster'), path('cluster/', views.ClusterTestView.as_view(), name='cluster'),
path('vch-upload/', views.upload_vch_load_from_html, name='vch_load'), path('vch-upload/', views.UploadVchLoadView.as_view(), name='vch_load'),
path('vch-link/', views.link_vch_sigma, name='link_vch_sigma'), path('vch-link/', views.LinkVchSigmaView.as_view(), name='link_vch_sigma'),
# path('upload/', views.upload_file, name='upload_file'), # path('upload/', views.upload_file, name='upload_file'),
] ]

View File

@@ -3,6 +3,10 @@ from django.contrib import messages
from django.http import JsonResponse from django.http import JsonResponse
from django.views.decorators.http import require_GET from django.views.decorators.http import require_GET
from django.contrib.admin.views.decorators import staff_member_required from django.contrib.admin.views.decorators import staff_member_required
from django.utils.decorators import method_decorator
from django.views import View
from django.views.generic import TemplateView, FormView
from django.contrib.auth.mixins import UserPassesTestMixin
import pandas as pd import pandas as pd
from .utils import ( from .utils import (
fill_data_from_df, fill_data_from_df,
@@ -18,50 +22,54 @@ from .clusters import get_clusters
from dbapp.settings import BASE_DIR from dbapp.settings import BASE_DIR
def add_satellites(request): class AddSatellitesView(View):
def get(self, request):
add_satellite_list() add_satellite_list()
return redirect('home') return redirect('home')
def add_transponders(request): class AddTranspondersView(View):
def get(self, request):
try: try:
parse_transponders_from_json(BASE_DIR / "transponders.json") parse_transponders_from_json(BASE_DIR / "transponders.json")
except FileNotFoundError: except FileNotFoundError:
print("Файл не найден") print("Файл не найден")
return redirect('home') return redirect('home')
class HomePageView(TemplateView):
def home_page(request): template_name = 'mainapp/home.html'
return render(request, 'mainapp/home.html')
def load_excel_data(request): class LoadExcelDataView(FormView):
if request.method == "POST": template_name = 'mainapp/add_data_from_excel.html'
form = LoadExcelData(request.POST, request.FILES) form_class = LoadExcelData
if form.is_valid():
uploaded_file = request.FILES['file'] def form_valid(self, form):
uploaded_file = self.request.FILES['file']
selected_sat = form.cleaned_data['sat_choice'] selected_sat = form.cleaned_data['sat_choice']
number = form.cleaned_data['number_input'] number = form.cleaned_data['number_input']
try: try:
# Create a temporary file-like object from the uploaded file
import io import io
df = pd.read_excel(io.BytesIO(uploaded_file.read())) df = pd.read_excel(io.BytesIO(uploaded_file.read()))
if number > 0: if number > 0:
df = df.head(number) df = df.head(number)
result = fill_data_from_df(df, selected_sat) result = fill_data_from_df(df, selected_sat)
messages.success(request, f"Данные успешно загружены! Обработано строк: {result}") messages.success(self.request, f"Данные успешно загружены! Обработано строк: {result}")
return redirect('load_excel_data') return redirect('load_excel_data')
except Exception as e: except Exception as e:
messages.error(request, f"Ошибка при обработке файла: {str(e)}") messages.error(self.request, f"Ошибка при обработке файла: {str(e)}")
return redirect('load_excel_data') return redirect('load_excel_data')
else:
form = LoadExcelData()
return render(request, 'mainapp/add_data_from_excel.html', {'form': form}) def form_invalid(self, form):
messages.error(self.request, "Форма заполнена некорректно.")
return super().form_invalid(form)
def get_locations(request, sat_id): from django.views.generic import View
class GetLocationsView(View):
def get(self, request, sat_id):
locations = ObjItem.objects.filter(id_vch_load__id_satellite=sat_id) locations = ObjItem.objects.filter(id_vch_load__id_satellite=sat_id)
if not locations: if not locations:
return JsonResponse({'error': 'Объектов не найдено'}, status=400) return JsonResponse({'error': 'Объектов не найдено'}, status=400)
@@ -87,11 +95,12 @@ def get_locations(request, sat_id):
"features": features "features": features
}) })
def load_raw_csv_data(request): class LoadCsvDataView(FormView):
if request.method == "POST": template_name = 'mainapp/add_data_from_csv.html'
form = LoadCsvData(request.POST, request.FILES) form_class = LoadCsvData
if form.is_valid():
uploaded_file = request.FILES['file'] def form_valid(self, form):
uploaded_file = self.request.FILES['file']
try: try:
# Read the file content and pass it directly to the function # Read the file content and pass it directly to the function
content = uploaded_file.read() content = uploaded_file.read()
@@ -99,16 +108,15 @@ def load_raw_csv_data(request):
content = content.decode('utf-8') content = content.decode('utf-8')
get_points_from_csv(content) get_points_from_csv(content)
messages.success(request, f"Данные успешно загружены!") messages.success(self.request, f"Данные успешно загружены!")
return redirect('load_csv_data') return redirect('load_csv_data')
except Exception as e: except Exception as e:
messages.error(request, f"Ошибка при обработке файла: {str(e)}") messages.error(self.request, f"Ошибка при обработке файла: {str(e)}")
return redirect('load_csv_data') return redirect('load_csv_data')
else: def form_invalid(self, form):
form = LoadCsvData() messages.error(self.request, "Форма заполнена некорректно.")
return super().form_invalid(form)
return render(request, 'mainapp/add_data_from_csv.html', {'form': form})
# def upload_file(request): # def upload_file(request):
# if request.method == 'POST' and request.FILES: # if request.method == 'POST' and request.FILES:
@@ -127,8 +135,13 @@ def load_raw_csv_data(request):
# return JsonResponse({'status': 'error', 'errors': form.errors}, status=400) # return JsonResponse({'status': 'error', 'errors': form.errors}, status=400)
# return render(request, 'mainapp/add_data_from_csv.html') # return render(request, 'mainapp/add_data_from_csv.html')
from collections import defaultdict from collections import defaultdict
@staff_member_required
def show_map_view(request): @method_decorator(staff_member_required, name='dispatch')
class ShowMapView(UserPassesTestMixin, View):
def test_func(self):
return self.request.user.is_staff
def get(self, request):
ids = request.GET.get('ids', '') ids = request.GET.get('ids', '')
points = [] points = []
if ids: if ids:
@@ -165,7 +178,8 @@ def show_map_view(request):
return render(request, 'admin/map_custom.html', context) return render(request, 'admin/map_custom.html', context)
def cluster_test(request): class ClusterTestView(View):
def get(self, request):
objs = ObjItem.objects.filter(name__icontains="! Astra 4A 12654,040 [1,962] МГц H") objs = ObjItem.objects.filter(name__icontains="! Astra 4A 12654,040 [1,962] МГц H")
coords = [] coords = []
for obj in objs: for obj in objs:
@@ -174,40 +188,40 @@ def cluster_test(request):
return JsonResponse({"success": "ок"}) return JsonResponse({"success": "ок"})
def upload_vch_load_from_html(request): class UploadVchLoadView(FormView):
if request.method == 'POST': template_name = 'mainapp/upload_html.html'
form = UploadFileForm(request.POST, request.FILES) form_class = UploadFileForm
if form.is_valid():
def form_valid(self, form):
selected_sat = form.cleaned_data['sat_choice'] selected_sat = form.cleaned_data['sat_choice']
uploaded_file = request.FILES['file'] uploaded_file = self.request.FILES['file']
try: try:
get_vch_load_from_html(uploaded_file, selected_sat) get_vch_load_from_html(uploaded_file, selected_sat)
messages.success(request, "Файл успешно обработан") messages.success(self.request, "Файл успешно обработан")
except ValueError as e: except ValueError as e:
messages.error(request, f"Ошибка при чтении таблиц: {e}") messages.error(self.request, f"Ошибка при чтении таблиц: {e}")
except Exception as e: except Exception as e:
messages.error(request, f"Неизвестная ошибка: {e}") messages.error(self.request, f"Неизвестная ошибка: {e}")
else: return redirect('vch_load')
messages.error(request, "Форма заполнена некорректно.")
else:
form = UploadFileForm()
return render(request, 'mainapp/upload_html.html', {'form': form}) def form_invalid(self, form):
messages.error(self.request, "Форма заполнена некорректно.")
return super().form_invalid(form)
def link_vch_sigma(request): class LinkVchSigmaView(FormView):
if request.method == 'POST': template_name = 'mainapp/link_vch.html'
form = VchLinkForm(request.POST) form_class = VchLinkForm
if form.is_valid():
def form_valid(self, form):
freq = form.cleaned_data['value1'] freq = form.cleaned_data['value1']
freq_range = form.cleaned_data['value2'] freq_range = form.cleaned_data['value2']
ku_range = float(form.cleaned_data['ku_range']) ku_range = float(form.cleaned_data['ku_range'])
sat_id = form.cleaned_data['sat_choice'] sat_id = form.cleaned_data['sat_choice']
# print(freq, freq_range, ku_range, sat_id.pk) # print(freq, freq_range, ku_range, sat_id.pk)
count_all, link_count = compare_and_link_vch_load(sat_id, freq, freq_range, ku_range) count_all, link_count = compare_and_link_vch_load(sat_id, freq, freq_range, ku_range)
messages.success(request, f"Привязано {link_count} из {count_all} объектов") messages.success(self.request, f"Привязано {link_count} из {count_all} объектов")
return redirect('link_vch_sigma') return redirect('link_vch_sigma')
else:
form = VchLinkForm()
return render(request, 'mainapp/link_vch.html', {'form': form}) def form_invalid(self, form):
return self.render_to_response(self.get_context_data(form=form))

View File

@@ -5,11 +5,11 @@ from . import views
urlpatterns = [ urlpatterns = [
path('3dmap', views.cesium_map, name='3dmap'), path('3dmap', views.CesiumMapView.as_view(), name='3dmap'),
path('2dmap', views.leaflet_map, name='2dmap'), path('2dmap', views.LeafletMapView.as_view(), name='2dmap'),
path('api/footprint-names/<int:sat_id>', views.get_footprints, name="footprint_names"), path('api/footprint-names/<int:sat_id>', views.GetFootprintsView.as_view(), name="footprint_names"),
path('api/transponders/<int:sat_id>', views.get_transponder_on_satid, name='transponders_data'), path('api/transponders/<int:sat_id>', views.GetTransponderOnSatIdView.as_view(), name='transponders_data'),
path('tiles/<str:footprint_name>/<int:z>/<int:x>/<int:y>.png', views.tile_proxy, name='tile_proxy'), path('tiles/<str:footprint_name>/<int:z>/<int:x>/<int:y>.png', views.TileProxyView.as_view(), name='tile_proxy'),
# path('', views.home_page, name='home'), # path('', views.home_page, name='home'),
# path('excel-data', views.load_excel_data, name='load_excel_data'), # path('excel-data', views.load_excel_data, name='load_excel_data'),
# path('satellites', views.add_satellites, name='add_sats'), # path('satellites', views.add_satellites, name='add_sats'),

View File

@@ -5,16 +5,23 @@ from django.core import serializers
from django.http import HttpResponse, HttpResponseNotFound from django.http import HttpResponse, HttpResponseNotFound
from django.views.decorators.cache import cache_page from django.views.decorators.cache import cache_page
from django.views.decorators.http import require_GET from django.views.decorators.http import require_GET
from django.utils.decorators import method_decorator
from django.views import View
from django.views.generic import TemplateView
from mainapp.models import Satellite from mainapp.models import Satellite
from .models import Transponders from .models import Transponders
from .utils import get_band_names from .utils import get_band_names
def cesium_map(request): class CesiumMapView(TemplateView):
sats = Satellite.objects.all() template_name = 'mapsapp/map3d.html'
return render(request, 'mapsapp/map3d.html', {'sats': sats}) def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['sats'] = Satellite.objects.all()
return context
def get_footprints(request, sat_id): class GetFootprintsView(View):
def get(self, request, sat_id):
try: try:
sat_name = Satellite.objects.get(id=sat_id).name sat_name = Satellite.objects.get(id=sat_id).name
footprint_names = get_band_names(sat_name) footprint_names = get_band_names(sat_name)
@@ -24,9 +31,13 @@ def get_footprints(request, sat_id):
return JsonResponse({"error": str(e)}, status=400) return JsonResponse({"error": str(e)}, status=400)
@require_GET class TileProxyView(View):
@cache_page(60 * 60 * 24) @method_decorator(require_GET)
def tile_proxy(request, footprint_name, z, x, y): @method_decorator(cache_page(60 * 60 * 24)) # Cache for 24 hours
def dispatch(self, *args, **kwargs):
return super().dispatch(*args, **kwargs)
def get(self, request, footprint_name, z, x, y):
if not footprint_name.replace('-', '').replace('_', '').isalnum(): if not footprint_name.replace('-', '').replace('_', '').isalnum():
return HttpResponse("Invalid footprint name", status=400) return HttpResponse("Invalid footprint name", status=400)
@@ -43,13 +54,18 @@ def tile_proxy(request, footprint_name, z, x, y):
except Exception as e: except Exception as e:
return HttpResponse(f"Proxy error: {e}", status=500) return HttpResponse(f"Proxy error: {e}", status=500)
def leaflet_map(request): class LeafletMapView(TemplateView):
sats = Satellite.objects.all() template_name = 'mapsapp/map2d.html'
trans = Transponders.objects.all()
return render(request, 'mapsapp/map2d.html', {'sats': sats, 'trans': trans}) def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['sats'] = Satellite.objects.all()
context['trans'] = Transponders.objects.all()
return context
def get_transponder_on_satid(request, sat_id): class GetTransponderOnSatIdView(View):
def get(self, request, sat_id):
trans = Transponders.objects.filter(sat_id=sat_id) trans = Transponders.objects.filter(sat_id=sat_id)
output = [] output = []
for tran in trans: for tran in trans:

View File