Crear un proyecto compartible de QGIS con conexiones a PostgreSQL/PostGIS

19/06/2023Por iCarto

Una de las numerosas características que nos ofrece QGIS es la de poder guardar nuestros proyectos. Podemos almacenar en un fichero todas las configuraciones específicas, capas, estilos, análisis, entre otros aspectos, permitiéndonos así volver a ese punto en cualquier momento. Esto resulta muy útil sobre todo cuando se trata de la organización de proyectos complejos. Esta funcionalidad es además de mucha ayuda de cara al trabajo colaborativo, ya que podemos intercambiarlos con otras personas del equipo.

Sin embargo, cuando creamos un proyecto para ser compartido, tenemos que tener en cuenta algunos aspectos, como por ejemplo cuando en él se incluyen conexiones a una base de datos. En este artículo comentaremos algunas claves interesantes para hacer esto.

Conexiones a base de datos en proyectos de QGIS: La forma recomendada de hacerlo

La mayoría de veces que se crea un proyecto de QGIS con capas en PostgreSQL/PostGIS se hace escribiendo directamente los datos de la conexión, lo que incluye almacenar la contraseña en texto claro en el proyecto.

Cuando se hace de este modo, dentro del fichero de proyecto que crea QGIS, con extensión .qgz/.qgs, habrá una línea como esta:

<datasource>dbname='test' host=localhost port=5439 user='test_user' password='test_user' sslmode=disable key='id' srid=4326 type=Point checkPrimaryKeyUnicity='0' table="public"."cities" (geom)</datasource>

Esto genera muchos problemas a la hora de pasar el proyecto «a producción» o compartirlo con otras personas:

  • Los usuarios y contraseñas deben ser compartidos entre varias personas, con lo que no se pueden establecer permisos individuales o grupales de una forma lógica.
  • Si no hardcodeamos el usuario y la contraseña cada persona que use el proyecto tendrá que introducir cada vez los datos.
  • Las contraseñas se almacenan en texto claro
  • Si hay que cambiar el servidor por ejemplo para pasar del entorno de test al de producción, hay que modificar el proyecto.

Si bien hay algunas formas de mejorar un poco esto: usar .pgpass, usar el Authentication Manager, usar algún script a medida empotrado en el proyecto, … no son la mejor opción y tienen problemas.

La mejor forma, o al menos la que por nuestra experiencia podemos recomendar, es asociar los datos de conexión a un identificador (un nombre que hayamos acordado), y en QGIS establecer la conexión mediante el mismo.

PostgreSQL permite hacer esto mediante el Connection Service File. Un fichero de texto ubicado en Linux en ~/.pg_service.conf y en Windows en %APPDATA%\postgresql\.pg_service.conf que tendría un aspecto como este:

[test]
host=localhost
port=5439
dbname=test
user=test_user
password=test_user
sslmode=disable

# Avoid hardcoding the password in prod
[production]
host=my.production.server
port=5432
dbname=my_project
user=my_user

host=my.production.server port=5432 dbname=my_project user=my_user

Y en QGIS se establecería la conexión así:

Donde sólo es necesario rellenar el nombre de la conexión y el nombre del servicio, que será nuestro identificador (el texto entre corchetes) en el fichero .pg_service.conf. Esto está explicado con más detalle en la documentación de QGIS.

Las ventajas de usar conexiones con un identificador son claras y resuelven los problemas mencionados arriba. Una persona puede preparar el proyecto en local, después, cuando pasa a producción sólo tiene que enviar el proyecto, e indicar el nombre de la conexión y los parámetros que el resto del equipo deberá rellenar en el .pg_service.conf

Además dado que este fichero es gestionado directamente por libpq, la librería estándar de cliente para conectar a PostgreSQL, que usan el 99% de las aplicaciones, esta estrategia funcionará con cualquier otro cliente que vaya a hacer uso de esa conexión de base de datos, no sólo QGIS.

Por ejemplo en comandos de consola:

ogrinfo PG:"service=test" cities
psql service=test

o en scripts de QGIS:

layer = QgsVectorLayer("service=test table=cities (geom)", "Cities", "postgres")
QgsProject.instance().addMapLayer(layer)

En el Service File se pueden definir un montón de parámetros y pocos son obligatorios. Por ejemplo, si no definimos la contraseña, cualquier aplicación que use libpq ejecutará un workflow normal para tratar de descubrirla: buscar en la variable PGPASSWORD, en el fichero .pgpass si existe, o preguntarnos por pantalla directamente para que se la demos.