27 Jul 2021 Geolocalización con GeoDjango
En Geolocalización con Django-Leaflet ya vimos cómo podemos incorporar datos geográficos con Django mediante el uso de campos JSON. En este post iremos un poco más allá y exploraremos algunas de las ventajas de usar GeoDjango para la manipulación y consumo de información geográfica.
Comparativa general entre GeoDjango y Django Leaflet
Mediante campos de tipo JSON es fácil mantener una base de datos de puntos. En muchos casos eso es suficiente y podemos incluso programar pequeñas rutinas que hagan uso de algún otro componente para resolver algunas operaciones espaciales básicas.
Pero sin una base de datos espacial que almacene los datos siempre tendremos limitaciones y el desarrollo puede ser más laborioso.
La gran diferencia entre usar GeoDjango y campos de tipo JSON es que el primero hace uso de las capacidades espaciales de la base de datos (PostGIS, Spatialite,…) mientras que en el segundo caso la base de datos no tiene ninguna capacidad espacial.
Esto, aunque a priori puede implicar algún trabajo más de instalación y configuración, a la larga nos puede reportar grandes beneficios en proyectos de mayor dimensión.
Si bien con ambos podemos tener un componente de mapa (widget) que podemos añadir fácilmente a nuestro Django Admin, con GeoDjango tenemos algunas funcionalidades adicionales que no obtenemos con el uso de campos JSON.
Carga de datos
Con campos JSON a menudo tendremos que recurrir a scripts propios para la carga de los datos o a un proceso de preparación previo de esos datos. Con GeoDjango la carga de un fichero en formato GIS es mucho más fácil.
En primer lugar, GeoDjango nos ofrece un comando para generar automáticamente el modelo de nuestro dataset GIS. Con el comando ogrinspect
podemos generar ese modelo de la siguiente manera:
python manage.py ogrinspect data/bm5mv21sh0tpc1_20200601_0.shp Comarca --srid=25831 --multi --mapping
Donde indicamos, separados por espacios:
- el fichero que contiene los datos (en este caso un shapefile con las comarcas de Catalunya)
- el nombre que queremos usar para el modelo de Django
- el sistema de referencia (–srid) usado en la definición de las geometrías
- que las geometrías producidas sean de tipo MultiPolygon (–multi).
- que nos genere un diccionario para relacionar cada campo del modelo con el campo del shapefile (–mapping).
El comando anterior genera este resultado:
# This is an auto-generated Django model module created by ogrinspect.
from django.contrib.gis.db import models
class Comarca(models.Model):
codicomar = models.CharField(max_length=2)
nomcomar = models.CharField(max_length=20)
areacomar = models.FloatField()
dataalta = models.CharField(max_length=12)
geom = models.MultiPolygonField(srid=25831)
# Auto-generated `LayerMapping` dictionary for Comarca model
comarca_mapping = {
'codicomar': 'CODICOMAR',
'nomcomar': 'NOMCOMAR',
'areacomar': 'AREACOMAR',
'dataalta': 'DATAALTA',
'geom': 'MULTIPOLYGON',
}
Si guardamos esto en nuestro fichero models.py
ya podemos sincronizar la base de datos con:
python manage.py makemigrations
python manage.py migrate
Y, por último, ya podemos cargar nuestro fichero shapefile:
(env) usuario@unigis:~/Blog/GeoDjango$ python manage.py shell
>>> from app.models import Comarca, comarca_mapping
>>> from django.contrib.gis.utils import LayerMapping
>>> datos = 'data/bm5mv21sh0tpc1_20200601_0.shp'
>>> lm = LayerMapping(Comarca, datos, comarca_mapping, transform=False)
>>> lm.save()
Consultas espaciales
Con GeoDjango, las consultas espaciales vienen integradas en el ORM (Object-Relation Mapping), añadiendo un nuevo conjunto de lookups para ello. Por ejemplo:
>>> from django.contrib.gis.geos import Point
>>> pnt = Point(2.018602, 41.736041, srid=4326)
>>> Comarca.objects.filter(geom__contains=pnt)
<QuerySet [<Comarca: Comarca object (42)>]>
Esto evita que tengamos que recurrir a algoritmos propios para hacer algunas consultas y nos permite usar el mismo lenguaje tanto para las consultas sobre la información alfanumérica como para las que se hacen sobre la información geográfica. Eso repercute en un código más simple y más fácil de mantener y de evitar errores.
Además de eso, en este ejemplo ocurre otra cosa interesante. En nuestro modelo, nuestros datos están almacenados con el SRID 25831 y el punto lo hemos definido en 4326 y, sin embargo, la consulta nos devuelve el resultado correcto. GeoDjango hace la transformación automáticamente cuando sabe que ambos objetos o classes usan sistemas de referencia distintos.
Conclusión
En esta serie de posts sobre frameworks para el desarrollo de aplicaciones webmap, hemos visto otra alternativa para producir sitios web que nos permitan gestionar nuestros datos geográficos. Además de poder usar Django Leaflet para incorporar funcionalidades espaciales sin usar una base de datos espacial también podemos usar GeoDjango para aumentar las funcionalidades disponibles y poder cargar datos o realizar consultas espaciales con los propios mecanismos de Django.
Podéis encontrar más información sobre GeoDjango en el sitio oficial.