10 Desarrollo de aplicaciones geoespaciales de pila completa (full stack) con GeoDjango
10.1 Introducción
GeoDjango es una extensión de Django, un popular marco de trabajo web de Python, que permite desarrollar aplicaciones geoespaciales, tanto para la capa de backend (acceso a los datos) como para la capa de frontend (interfaz de usuario).
Un marco de trabajo (framework) es una estructura reutilizable que proporciona una base para el desarrollo de un proyecto de sofware. Usualmente, un marco de trabajo incluye bibliotecas y un conjunto de mejores prácticas para utilizarlas. El uso de un marco de trabajo permite un desarrollo más rápido, al proporcionar los componentes esenciales de un proyecto y dotarlos de funcionalidades básicas, que de otro modo habría que desarrollar completamente.
10.2 Django
Django fue desarrollado originalmente para gestionar páginas web orientadas a noticias de la World Company de Lawrence, Kansas. En 2005, fue liberado al público con una licencia BSD. Fue nombrado al guitarrista de jazz gitano Django Reinhardt.
10.2.1 Estructura de proyectos
10.2.1.1 Directorio principal
Un proyecto Django reside en un directorio del sistema de archivos, el cual contiene varios archivos y subdirectorios. Por ejemplo, el directorio de un proyecto llamado miproyecto
, tendría una estructura inicial como la siguiente:
miproyecto/
manage.py
miproyecto/
__init__.py
settings.py
urls.py
asgi.py
wsgi.py
Seguidamente, se describen los principales componentes de esta estructura:
- El directorio raíz externo
miproyecto/
es un contenedor para el proyecto. Puede tener cualquier nombre. manage.py
: es un utilitario de línea de comandos que permite realizar varias tareas administrativas, como ejecutar el proyecto y revisar su consistencia.- El directorio interno
miproyecto/
es el paquete de Python correspondiente al proyecto.miproyecto/__init__.py
: un archivo vacío que le dice a Python que este directorio debe considerarse un paquete.miproyecto/settings.py
: configuración del proyecto (aplicaciones, conexiones a bases de datos).miproyecto/urls.py
: conjunto de URL que utiliza el proyecto (ej. para acceder a las vistas).miproyecto/asgi.py
: punto de entrada para servidores web compatibles con ASGI.miproyecto/wsgi.py
: punto de entrada para servidores web compatibles con WSGI.
10.2.1.2 Aplicaciones
Un proyecto contiene varias aplicaciones. Algunas están incorporadas por defecto en cualquier proyecto. Un programador también puede desarrollar sus propias aplicaciones.
Al crear una aplicación llamada miaplicacion
, se genera un directorio como el siguiente:
miaplicacion/
__init__.py
admin.py
apps.py
migrations/
__init__.py
models.py
tests.py
views.py
Las aplicaciones de un proyecto se listan en un vector del archivo settings.py
llamado INSTALLED_APPS
, como el que se muestra seguidamente:
= [
INSTALLED_APPS 'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles'
]
Si se incluyen o se crean nuevas aplicaciones para este proyecto, deben agregarse al vector INSTALLED_APPS
.
10.2.2 El patrón Modelo–Vista–Controlador
La arquitectura de Django está basada en el patrón de diseño de software denominado Modelo-Vista-Controlador (MVC), el cual es muy popular en el desarrollo de aplicaciones y sus interfaces de usuario. El patrón consiste de tres componentes, los cuales se muestran en la Figura 10.1.
10.2.2.1 Modelo
El modelo es la representación interna de los datos. En el caso de Django, esta representación se implementa mediante clases de Python, las cuales se definen en el archivo models.py
de cada aplicación.
Django utiliza ORM (Object Relational Mapping), o mapeo relacional de objetos, para mapear las clases definidas en models.py
a las tablas de una base de datos. Esto permite utilizar el paradigma de programación orientada a objetos para manipular la base de datos. Se puede considerar un ORM como una herramienta para convertir los objetos Python de una aplicación a un formato adecuado para ser almacenados en sistemas administradores de bases de datos como Oracle, MySQL, PostgreSQL o SQLite.
10.2.2.2 Vista
Una vista presenta un modelo (i.e. datos) en un formato adecuado. Las vistas se definen en el archivo views.py
de cada aplicación.
10.2.2.3 Controlador
Responde a eventos e invoca peticiones al modelo cuando se hace alguna solicitud de información (ej. editar un documento o un registro en una base de datos). El controlador funciona como un “intermediario” entre el modelo y la vista.
10.2.3 Frontend y Backend
Django es marco de trabajo de “pila completa” (full stack), lo que significa que apoya el desarrollo de las dos grandes capas de la arquitectura de un sistema de información: el frontend y el backend, cuya relación se muestra en la Figura 10.2:
El frontend es la capa con la que los usuarios finales interactúan directamente. Incluye todos los aspectos relacionados con la interfaz del usuario, tales como la disposición de los elementos en la pantalla, los estilos y las interacciones que se realizan a través de menús, botones y formularios para ingreso de datos, entre otras.
Por su parte, el backend se encarga del procesamiento de los datos y del funcionamiento interno. No es visible para los usuarios finales. Incluye servidores de aplicaciones, bases de datos y la lógica de aplicación necesaria para procesar las instrucciones que los usuarios envían a través del frontend y para retornar los resultados por la misma vía.
Esta arquitectura permite una clara separación de responsabilidades, donde el frontend se enfoca en la experiencia del usuario y el backend en la lógica de procesamiento y acceso a datos. Esto no solo mejora la organización del código y facilita el mantenimiento, sino que también permite modificar partes de la aplicación de manera independiente, mejorando la eficiencia y la capacidad de manejo de los datos.
10.2.4 El Django REST Framework
El Django REST Framework (DRF) es una biblioteca para la creación de interfaces de programación de aplicaciones (API) para la Web en Django. Es ampliamente utilizado en el desarrollo de servicios backend que necesitan proporcionar datos al frontend mediante solicitudes HTTP (Protocolo de transferencia de hipertexto).
10.3 GeoDjango
GeoDjango es un módulo de Django para el desarrollo de aplicaciones geoespaciales. Enriquece una aplicación Django capacidades como:
- Acceso a bases de datos espaciales.
- Consultas espaciales (relaciones topológicas, cálculo de área, cálculo de distancias, etc.).
- Creación y modificación de geometrías.
- Transformaciones entre sistemas de coordenadas.
Las aplicaciones desarrolladas con GeoDjango usualmente utilizan una base de datos espacial como PostgreSQL y su extensión PostGIS. También requieren de bibliotecas espaciales como GDAL.
10.4 Ejemplo de desarrollo de un proyecto en GeoDjango
En esta sección, a manera de ejemplo, se desarrolla un proyecto con GeoDjango. El proyecto permite la captura de datos de puntos de observación y la generación de un mapa de calor que muestra las zonas con mayor concentración de puntos.
El proyecto consiste de dos aplicaciones:
- Un backend en el que se definen los modelos y las vistas. Los datos se capturan mediante la interfaz de administración de Django y se almacenan en una base de datos PosgreSQL y su extensión espacial PostGIS.
- Un frontend que despliega el mapa de calor.
Las secciones subsiguientes muestran los pasos detallados del proceso de desarrollo del proyecto.
10.4.1 Instalación de herramientas
En esta sección, se detalla la instalación del marco de trabajo Django y la base de datos PostgreSQL y su extensión espacial PostGIS.
10.4.1.1 Django
En este proyecto se utiliza la versión 4.2 de Django. La instalación se realiza en un ambiente del administrador de paquetes Conda, el cual se crea mediante la distribución de Python llamada Miniconda. En el mismo ambiente, se instala la biblioteca geoespacial GDAL versión 3.0.4. Se eligieron estas versiones de Django y GDAL por razones de compatibilidad. También se instala el paquete de Python psycopg2 (para conexión a PostgreSQL) y el Django REST Framework.
1. Instale Miniconda.
2. Cree un ambiente conda:
# Actualización de Conda
conda update conda
# Borrado del ambiente (si es que existe)
# conda remove -n desarrollo_geodjango --all
# Creación del ambiente
conda create -n desarrollo_geodjango
# Activación del ambiente
conda activate desarrollo_geodjango
# Instalación de módulos
conda install -c conda-forge gdal=3.0.4
conda install -c conda-forge django
conda install -c conda-forge psycopg2
conda install -c conda-forge djangorestframework
conda install -c conda-forge djangorestframework-gis
# Desactivación del ambiente (para cuando termine de usarse)
# conda deactivate
3. Revise las versiones del software instalado:
# Versión de Python
python --version
> Python 3.8.15
# Versión de Django
python -m django --version
> 4.2.13
# Versión de GDAL
gdalinfo --version
> GDAL 3.0.4, released 2020/01/28
10.4.1.2 PostgreSQL y PostGIS
4. Instale PostgreSQL y PostGIS.
10.4.2 Creación de una base de datos espaciales
5. Cree una base de datos PostgreSQL llamada mapa_leaflet_postgis
que tenga la extensión postgis
.
10.4.3 Creación de un proyecto Django y sus aplicaciones
Se crea un proyecto Django con dos aplicaciones: una para el backend y otra para el frontend.
10.4.3.1 Creación del proyecto
6. Cree un proyecto Django:
# Creación
django-admin startproject mapa_leaflet_postgis
# Cambio de directorio
cd mapa_leaflet_postgis
# Revisión
python manage.py check
> System check identified no issues (0 silenced).
# Ejecución del servidor
python manage.py runserver
El servidor debe estar disponible en la dirección http://127.0.0.1:8000/.
10.4.3.2 Creación de las aplicaciones
7. Cree una aplicación para el backend y otra para el frontend.
django-admin startapp mapa_backend
django-admin startapp mapa_frontend
10.5 Configuración de Django y GeoDjango
10.5.1 Adición de aplicaciones
8. Edite el archivo mapa_leaflet_postgis/settings.py
y en el vector INSTALLED_APPS
agregue las aplicaciones:
django.contrib.gis
(GeoDjango).rest_framework
(DRF).rest_framework_gis
(funciones espaciales del DRF).mapa_backend.apps.MapaBackendConfig
(backend).mapa_frontend.apps.MapaFrontendConfig
(frontend).
= [
INSTALLED_APPS 'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.gis',
'rest_framework',
'rest_framework_gis',
'mapa_backend.apps.MapaBackendConfig',
'mapa_frontend.apps.MapaFrontendConfig'
]
10.5.2 Configuración de la conexión a la base de datos
9. Edite el archivo mapa_leaflet_postgis/settings.py
y en el objeto DATABASES
especifique la conexión a la base de datos espaciales que creó:
= {
DATABASES 'default': {
'ENGINE': 'django.contrib.gis.db.backends.postgis',
'NAME': 'mapa_leaflet_postgis',
'USER': 'postgres',
'PASSWORD': 'postgres',
'HOST': 'localhost',
'PORT': '5432'
} }
10. Revise la configuración:
# Revisión
python manage.py check
> System check identified no issues (0 silenced).
10.5.3 Eliminación de los mensajes de migraciones no aplicadas
11. Elimine los mensajes de “migraciones” no aplicadas (se están desplegando al ejecutar el servidor):
# Comando migrate
python manage.py migrate
# Ejecución del servidor (para revisar)
python manage.py runserver
10.5.4 Creación de un superusuario
Un superusuario tiene todos los privilegios en la interfaz de administración de Django. En las próximas secciones, se utilizará el superusuario para ingresar datos mediante esa interfaz.
11. Cree un superusuario para la intefaz de administración de Django:
# Creación del superusuario
python manage.py createsuperuser
12. Verifique el acceso en http://127.0.0.1:8000/admin/.
10.6 Desarrollo del backend
10.6.1 Modelos
13. Edite el archivo mapa_backend/models.py
y agregue un modelo llamado Observacion
:
from django.db import models
from django.contrib.gis.db import models
class Observacion(models.Model):
= models.CharField("Nombre de la observación", max_length=50, help_text="Nombre de la observación")
nombre = models.CharField("Descripción de la observación", max_length=254, blank=True, help_text="Descripción de la observación")
descripcion = models.PointField()
ubicacion
class Meta:
= "Observaciones"
verbose_name_plural
def __str__(self):
return self.nombre
14. Realice la “migración” de los modelos:
# Comando makemigrations
python manage.py makemigrations mapa_backend
# Comando migrate
python manage.py migrate
15. Revise los archivos de migración en la carpeta mapa_backend/migrations
y la tabla mapa_backend_observacion
en la base de datos mapa_leaflet_postgis
. Ambos deben haberse creado como producto de los comandos anteriores.
10.6.2 Configuración de la interfaz de administración
16. Edite el archivo mapa_backend/admin.py
:
from django.contrib.gis import admin
from .models import Observacion
# Register your models here.
class CustomGeoAdmin(admin.GISModelAdmin):
= {
gis_widget_kwargs 'attrs': {
'default_zoom': 7,
'default_lon': -84.0,
'default_lat': 10.0
}
}
@admin.register(Observacion)
class ObservacionAdmin(CustomGeoAdmin):
pass
17. Pruebe la interfaz de administración en http://127.0.0.1:8000/admin/ y agregue algunos registros de observaciones.
**18. Confirme que las observaciones se hayan agregado a la tabla mapa_backend_observacion
en la base de datos mapa_leaflet_postgis
.
10.6.3 Vistas
De acuerdo con el patrón Modelo - Vista - Controlador (MVC), una vista es una interfaz que presenta información al usuario. En el caso de Django, la presenta por medio de documentos web (i.e. a través del protocolo HTTP). Cada vista recibe una solicitud (request) y retorna una respuesta (response).
10.6.3.1 Ejemplo
Primero, a manera de ejemplo, se crea una vista muy sencilla.
19. Edite el archivo mapa_backend/views.py
:
from django.shortcuts import render
from django.http import HttpResponse
# Create your views here.
def hello_world(request):
return HttpResponse("Hola mundo")
Cada vista debe estar asociada a un URL.
20. Cree el archivo mapa_backend/urls.py
y agregue el siguiente contenido:
from django.urls import path
from . import views
= [
urlpatterns "", views.hello_world, name="hello_world")
path( ]
El URL que acaba de crearse en la aplicación mapa_backend
debe enlazarse con el archivo de URL del proyecto.
21. Edite el archivo mapa_leaflet_postgis/urls.py
:
from django.contrib import admin
from django.urls import path, include
= [
urlpatterns 'admin/', admin.site.urls),
path("", include("mapa_backend.urls"))
path( ]
De esta manera, los URL de la aplicación quedan enlazados con los URL del proyecto.
22. Verifique el acceso la vista hello_world
en http://127.0.0.1:8000/.
Ejercicio: cambie la hilera vacía del URL por backend/
y trate de accederlo.
10.6.3.2 Recuperación de todos los objetos de un modelo
En un nuestro caso, lo que deseamos es consultar una base de datos espacial y obtener respuestas en formato GeoJSON (en el caso de datos vectoriales). Para lograr esto, es necesario realizar una serialización de los modelos. En este caso, significa transformar el contenido de la base de datos al formato GeoJSON.
23. Agregue una vista para el modelo Observacion
en mapa_backend/views.py
:
from django.shortcuts import render
from django.http import HttpResponse
from django.core.serializers import serialize
from .models import Observacion
# Create your views here.
def observaciones(request):
= Observacion.objects.all()
consulta = serialize("geojson", consulta, geometry_field="ubicacion", srid=3857)
geojson return HttpResponse(geojson, content_type="application/json")
La vista anterior:
- Recupera todos los objetos del modelo
Observacion
a través de una consulta realizada mediante el API de Django. - Serializa el resultado de la consulta y lo convierte a GeoJSON.
- Retorna como respuesta la consuta en formato GeoJSON.
24. Para acceder a la vista, debe asociarse con un URL. Modifique de la siguiente forma el archivo mapa_backend/urls.py
:
from django.urls import path
from . import views
= [
urlpatterns "observaciones/", views.observaciones, name="observaciones")
path( ]
25. También debe modificar las URL del proyecto en el archivo mapa_leaflet_postgis/urls.py
:
from django.contrib import admin
from django.urls import path, include
= [
urlpatterns 'admin/', admin.site.urls),
path("api/v1/", include("mapa_backend.urls"))
path( ]
Puede acceder a la vista en: http://127.0.0.1:8000/api/v1/observaciones/
10.6.3.3 Recuperación de un objeto
Seguidamente, se crea una vista que recupera una observación según el valor del campo pk
(este campo se crea automáticamente).
26. Modifique el archivo mapa_backend/views.py
y agregue una función llamada observacion_por_llave()
:
from django.shortcuts import render
from django.http import HttpResponse
from django.core.serializers import serialize
from .models import Observacion
# Create your views here.
def observaciones(request):
= Observacion.objects.all()
consulta = serialize("geojson", consulta, geometry_field="ubicacion", srid=3857)
geojson return HttpResponse(geojson, content_type="application/json")
def observacion_por_llave(request, llave):
= Observacion.objects.get(pk=llave)
observacion = serialize("geojson", [observacion], geometry_field="ubicacion", srid=3857)
geojson return HttpResponse(geojson, content_type="application/json")
La función observacion_por_llave()
recibe (además de request
) el argumento llave
, el cual se utiliza para recuperar un objeto de tipo Observacion
, el cual se serializa y se retorna.
27. Para acceder a la vista, modifique de la siguiente forma el archivo mapa_backend/urls.py
:
from django.urls import path
from . import views
= [
urlpatterns "observaciones/", views.observaciones, name="observaciones"),
path("observacion_por_llave/<int:llave>", views.observacion_por_llave, name="observacion_por_llave")
path( ]
Acceda a la nueva vista con, por ejemplo, http://127.0.0.1:8000/api/v1/observacion_por_llave/1.
Ejercicios:
- Cree un modelo llamado
Ciudad
con los atributosnombre
,poblacion
ypoint_geom
. Ingrese algunos registros a través de la interfaz de administración de Django. - Cree una vista para recuperar los datos de todas las ciudades y otra para recuperar los datos de una ciudad por nombre.
10.6.4 Uso del DRF
En esta sección, se mostrará el uso del DRF en el backend.
28. Cree el archivo mapa_backend/serializers.py
y agregue un serializador para el modelo Observacion
, con el siguiente contenido:
from .models import Observacion
from rest_framework_gis.serializers import GeoFeatureModelSerializer
class ObservacionSerializador(GeoFeatureModelSerializer):
class Meta:
= Observacion
model = 'ubicacion'
geo_field
= (
fields 'pk',
'nombre',
'descripcion'
)
29. Utilice el serializador que acaba de crear en dos vistas. Edite el archivo mapa_backend/views.py
y agregue el siguiente contenido (puede eliminar o comenat el código de las vistas que creó en los pasos anteriores):
from .models import Observacion
from .models import Ciudad
from .serializers import ObservacionSerializador
from rest_framework import generics
# Create your views here.
class ObservacionLista(generics.ListAPIView):
= Observacion.objects.all()
queryset = ObservacionSerializador
serializer_class = 'observacion-lista'
name
class ObservacionDetalle(generics.RetrieveAPIView):
= Observacion.objects.all()
queryset = ObservacionSerializador
serializer_class = 'observacion-detalle' name
Puede ver la especificación técnica de las vistas genéricas del DRF en Generic views - Django REST Framework.
30. Para agregar los URL correspondientes a las vistas, edite el archivo mapa_backend/urls.py
y agregue el siguiente contenido (antes comente el código de los URL que creó en los pasos anteriores):
from django.urls import path
from . import views
= [
urlpatterns "observaciones/", views.ObservacionLista.as_view(), name=views.ObservacionLista.name),
path("observaciones/<int:pk>/", views.ObservacionDetalle.as_view(), name=views.ObservacionDetalle.name)
path( ]
Puede acceder a las vistas en:
Ejercicios
- Cambie a la vista genérica de la vista
ObservacionLista
aCreateAPIView
(https://www.django-rest-framework.org/api-guide/generic-views/#createapiview) y en cree una nueva observación en la interfaz web que se muestra al invocar la vista. - Cambie a la vista genérica de la vista
ObservacionDetalle
aRetrieveUpdateDestroyAPIView
(https://www.django-rest-framework.org/api-guide/generic-views/#retrieveupdatedestroyapiview) y modifique y borre observaciones en la interfaz web que se muestra al invocar la vista. - Cree un serializador para el modelo
Ciudad
y vistas para recuperar todos los objetos y un objeto por la llave primaria (pk
).
10.7 Desarrollo del frontend
El frontend recibe, mediante vistas, los datos contenidos en los modelos del backend y los despliega para el usuario. En este caso, se muestran en un mapa desarrollado en la bibioteca Leaflet.
10.7.1 Archivos estáticos
Las vistas acceden archivos JS y CSS. En este contexto, estos archivos se denominan “estáticos”, por tener contenido fijo o estático, a diferencia de las plantillas, que tienen contenido dinámico.
31. Cree los siguientes archivos estáticos en la aplicación frontend (note que debe crear algunos directorios también):
mapa_frontend/static/css/estilos.css
*{
box-sizing: border-box;
}
body {padding: 0;
margin: 0;
overflow: auto;
}
#mapaid {
height: 100vh;
width: 100vw;
}
mapa_frontend/static/js/principal.js
// Evento que se dispara al cargar la página web
document.addEventListener("DOMContentLoaded", iniciar)
// Función que se invoca con el disparo de "DOMContentLoaded"
function iniciar() {
// Objeto del mapa Leaflet
var mapa = L.map('mapaid').setView([9.5, -84], 8);
// Capa base de Carto
= L.tileLayer(
positromap "https://{s}.basemaps.cartocdn.com/light_nolabels/{z}/{x}/{y}{r}.png",
{attribution:
'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors © <a href="https://carto.com/attributions">CARTO</a>',
subdomains: "abcd",
maxZoom: 20,
}.addTo(mapa);
)
// Capa base de OSM
= L.tileLayer("https://tile.openstreetmap.org/{z}/{x}/{y}.png", {
osm maxZoom: 19,
attribution:
'© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
;
})
// Capa base de ESRI
= L.tileLayer(
esriworld "https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}",
{attribution:
"Tiles © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community",
};
)
// Objeto de capas base
var mapasbase = {
"Carto Positron": positromap,
OpenStreetMap: osm,
"ESRI WorldImagery": esriworld,
;
}
// Control de capas
= L.control
control_capas .layers(mapasbase, null, { collapsed: false })
.addTo(mapa);
// Función asíncrona que realiza una solicitud HTTP (tipo GET)
// a una URL especificada, procesa la respuesta JSON y luego
// ejecuta una función pasada como argumento con los datos JSON obtenidos.
const fetchGetRequest = async(url, func) => {
try {
const response = await fetch(url)
const json = await response.json()
return func(json)
catch (error) {
} console.log(error.message)
}
}
// Función que agrega los datos GeoJSON al mapa
const agregarObservacionesAlMapa = (json) => {
// console.log(json)
// Se obtienen los datos en GeoJSON
= L.geoJSON(json, {}).addTo(mapa);
observaciones
// Se agrgan los datos GeoJSON al mapa
.addOverlay(observaciones, "Observaciones");
control_capas
}
// Llamado a fetchGetRequest()
fetchGetRequest('/api/v1/observaciones', agregarObservacionesAlMapa)
}
10.7.2 Plantillas
Las plantillas (templates) son archivos HTML combinados con el Django Template Languaje (DTL). Estos archivos definen la estructura de las páginas web. Utilizan el DTL para incluir contenido dinámico, permiten incorporar datos provenientes de las vistas y pueden incluir etiquetas y filtros de Django para lógica básica y manipulación de datos.
32. Cree los archivos:
mapa_frontend/templates/mapa_frontend/base.html
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block titulo %}Observaciones{% endblock %}</title>
<!-- CSS -->
{% block enlaces_css %}{% endblock %}</head>
<body>
<!-- JS -->
{% block enlaces_js %}{% endblock %}
<div id="content">
{% block contenido %}{% endblock %}</div>
</body>
</html>
mapa_frontend/templates/mapa_frontend/observaciones_base.html
{% extends './base.html' %}
{% load static %}
{% block enlaces_css %}<!-- Enlace a hoja CSS de Leaflet -->
<link
rel="stylesheet"
href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css"
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY="
crossorigin=""
/>
<!-- Enlace a estilos del mapa -->
<link rel="stylesheet" href="{% static 'css/estilos.css' %}">
{% endblock %}
{% block enlaces_js %}<!-- Enlace a biblioteca JavaScript de Leaflet -->
<script
src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo="
crossorigin=""
></script>
<!-- Código JS/Leaflet para crear y configurar el mapa -->
<script src="{% static 'js/principal.js' %}"></script>
{% endblock %}
{% block contenido %}<div id="mapaid"></div>
{% endblock %}
10.7.3 Vistas
Las vistas del frontend retornan HTML, para lo que emplean el método render().
33. Edite el archivo mapa_frontend/views.py
:
from django.shortcuts import render
# Create your views here.
def observacionesListaMapa(request):
return render(request, 'mapa_frontend/observaciones_base.html')
34. Cree el archivo mapa_frontend/urls.py
y agregue el siguiente contenido:
from django.urls import path
from . import views
= 'mapa_frontend'
app_name = [
urlpatterns '', views.observacionesListaMapa, name='observaciones-lista-mapa')
path( ]
35. Edite el archivo mapa_leaflet_postgis/urls.py
:
from django.contrib import admin
from django.urls import path, include
= [
urlpatterns 'admin/', admin.site.urls),
path("api/v1/", include("mapa_backend.urls")),
path('', include('mapa_frontend.urls'))
path( ]
36. El mapa Leaflet con los puntos de observación ingresados por medio de la interfaz de administración de Django debe estar visible en la dirección http://127.0.0.1:8000/.
Ejercicios
- Agregue al mapa Leaflet una capa de puntos agrupados, con base en la capa de observaciones.
- Agregue al mapa Leaflet una capa de calor, con base en la capa de observaciones.
10.8 Carga de datos externos
En esta sección se muestra como cargar datos geoespaciales a través de GeoDjango para su uso en las aplicaciones.
37. Cree el directorio mapa_backend/datos y coloque ahí el archivo registros-presencia.gpkg.
Este archivo contiene un conjunto de registros de presencia de especies.
38. Ejecute el siguiente comando:
python manage.py ogrinspect mapa_backend/datos/registros-presencia.gpkg RegistroPresencia --mapping --name-field species --null true
Como salida, generará un modelo Django y un mapeo de campos que se utilizará en un script de Python.
39. Agregue el modelo a mapa_backend/models.py
(note los cambios en los argumentos max_length
)
class RegistroPresencia(models.Model):
= models.CharField(max_length=50, null=True)
species = models.CharField(max_length=50, null=True)
sex = models.IntegerField(null=True)
age = models.FloatField(null=True)
decimallongitude = models.FloatField(null=True)
decimallatitude = models.PointField()
geom
def __str__(self): return self.species
40. Revise la documentación en https://docs.djangoproject.com/en/4.1/ref/contrib/gis/tutorial/#layermapping y cree el archivo mapa_backend/load.py
:
from pathlib import Path
from django.contrib.gis.utils import LayerMapping
from .models import RegistroPresencia
= {
registropresencia_mapping 'species': 'species',
'sex': 'sex',
'age': 'age',
'decimallongitude': 'decimalLongitude',
'decimallatitude': 'decimalLatitude',
'geom': 'POINT',
}
= Path(__file__).resolve().parent / 'datos' / 'registros-presencia.gpkg'
registros_gpkg
def run(verbose=True):
= LayerMapping(RegistroPresencia, registros_gpkg, registropresencia_mapping, transform=False)
lm =True, verbose=verbose) lm.save(strict
41. Realice las migraciones:
python manage.py makemigrations
python manage.py migrate
42. Abra la interfaz de línea de comandos de Django:
python manage.py shell
43. Cargue los datos desde el archivo:
from mapa_backend import load
load.run()
44. Consulte los datos cargados:
from mapa_backend.models import RegistroPresencia
RegistroPresencia.objects.count()all()
RegistroPresencia.objects.id = 1)
RegistroPresencia.objects.get(id = 1).sex
RegistroPresencia.objects.get(filter(sex="Hembra")
RegistroPresencia.objects.filter(sex="Hembra").count()
RegistroPresencia.objects. exit()
45. Edite el archivo mapa_backend/admin.py
para incluir el modelo en la interfaz de administración de Django:
from django.contrib.gis import admin
from .models import Observacion
from .models import RegistroPresencia
# Register your models here.
class CustomGeoAdmin(admin.GISModelAdmin):
= {
gis_widget_kwargs 'attrs': {
'default_zoom': 7,
'default_lon': -84.0,
'default_lat': 10.0
}
}
@admin.register(Observacion)
class ObservacionAdmin(CustomGeoAdmin):
pass
@admin.register(RegistroPresencia)
class RegistroPresenciaAdmin(CustomGeoAdmin):
pass
Ejercicios
- Cree un serializador y una vista en modo lista para todas las instancias del modelo
RegistroPresencia
. - Cree los URL necesarios.
- Modifique la aplicación Leaflet para desplegar los registros de presencia.