16

How to add layers (vector or raster to an existing GeoPackage)?

While loading an existing layer of a GeoPackage is quite trivial:

from qgis.utils import iface

path = '/home/matteo/geopackage.gpkg|layername={}'.format('admin')
iface.addVectorLayer(path, 'admin', 'ogr')

I couldn't find information about adding them via PyQGIS.

1

4 Answers 4

14

Write a layer to a GeoPackage

The easiest way to save a vector layer to GeoPackage is to use the "Save vector features to file" algorithm, available from QGIS 3.16 on.

import processing

params = {'INPUT': existing_layer,
          'OUTPUT': '/tmp/new_gpkg.gpkg',
          'LAYER_NAME': 'new_layer_name'}
processing.run("native:savefeatures", params)

Note that you can pass additional GDAL/OGR options by passing DATASOURCE_OPTIONS and LAYER_OPTIONS parameters.

Warning: If you pass a path to an existing GeoPackage as OUTPUT parameter, this algorithm will replace your GeoPackage by a new one!!!

Adding an additional layer to an existing GeoPackage

Option 1

If you want to add a layer to an existing GeoPackage (and still preserve other existing layers!), you can use the GDAL's "Convert format" algorithm in this way:

import processing

params = {'INPUT': existing_layer,
          'OPTIONS':'-update -nln my_new_layer_name',
          'OUTPUT':'/tmp/existing_db.gpkg'}
processing.run("gdal:convertformat", params)

Where -update indicates the existing GeoPackage shouldn't be overwritten but updated, and -nln (optional) indicates the layer name you want your existing_layer to have when created into the existing GeoPackage.

Option 2

You could also use the "Package layers" algorithm, which allows you to add several layers at once, in this way:

import processing

params = {'LAYERS': [layer1, layer2],
          'OUTPUT': '/tmp/existing_db.gpkg',
          'OVERWRITE': False,  # Important!
          'SAVE_STYLES': False,
          'SAVE_METADATA': False,
          'SELECTED_FEATURES_ONLY': False}
processing.run("native:package", params)

Note: Set the rest of parameters as you like, but the OVERWRITE one should be set to False if you want to update the existing GeoPackage.

4
  • This seems to be directly creating a new geopackage from an existing layer. Is there a way to add an existing layer to an existing geopackage?
    – WFL.GIS
    Commented Aug 19, 2021 at 1:30
  • Just try passing as OUTPUT an existing GeoPackage file path, as the answers also suggests. Commented Aug 19, 2021 at 1:42
  • Yes, I used an existing gpkg as output and got an error message (it attempts to create a new gpkg with that name, and throws an error since it already exists). I was able to figure it out just now, though -- to add a new layer to an existing gpkg, "qgis:package" should be used instead.
    – WFL.GIS
    Commented Aug 19, 2021 at 2:00
  • 1
    You're actually right. I edited my answer to show a solution for your use case. Commented Aug 19, 2021 at 2:40
14

You need to use QgsVectorFileWriter.writeAsVectorFormat. If you store one layer per GPKG file you just need:

QGIS 3:

# imports
from qgis.utils import iface
from qgis.core import QgsProject, QgsVectorFileWriter

# get layer list by one of:
lyrs = iface.layerTreeView().selectedLayers()
lyrs = QgsProject.instance().layerTreeRoot().children()

# select layer
lyr = lyrs[0]
_writer = QgsVectorFileWriter.writeAsVectorFormat(lyr, r"C:\gisData\layer.gpkg")

QGIS 2:

# imports
from qgis.utils import iface
from qgis.core import QgsMapLayerRegistry, QgsVectorFileWriter

# get layer list by one of:
lyrs = iface.mapCanvas().layers() # OR
lyrs = QgsMapLayerRegistry.instance().mapLayers()

# select layer
lyr = lyrs[0]
_writer = QgsVectorFileWriter.writeAsVectorFormat(lyr, r"C:\gisData\layer.gpkg")

If you want save more than one layer in GeoPackage file you should set additional options.

from qgis.core import QgsMapLayer, QgsVectorFileWriter

for lyr in filter(lambda l: l.type() == QgsMapLayer.VectorLayer, lyrs):
    options = QgsVectorFileWriter.SaveVectorOptions()
    options.actionOnExistingFile = QgsVectorFileWriter.CreateOrOverwriteLayer 
    options.layerName = "_".join(lyr.name().split(' '))
    _writer = QgsVectorFileWriter.writeAsVectorFormat(lyr, gpkgPath, options)
    if _writer:
        print(lyr.name(), _writer)

PyQGIS should have similar interface for raster layers. In my opinion easiest way to find out is to install IPyConsole plugin and use PyQGIS API.

1
  • 2
    QgsMapLayerRegistry is gone in QGIS 3, but writeAsVectorFormat should still be there. Sidenote, there is also the QgsVectorLayerExporter class available. Commented Nov 2, 2018 at 7:38
7

I have investigated this code an create a script like it works very well for exporting raster layer to GeoPackage:

from osgeo import ogr
from qgis.core import QgsRasterLayer, QgsRasterFileWriter, QgsRasterPipe, QgsRasterProjector

ds = ogr.Open(self.projectGpkg, True)
source = QgsRasterLayer(layerSource, 'rasterLayer', 'gdal')

if source.isValid():
    provider = source.dataProvider()
    fw = QgsRasterFileWriter(self.projectGpkg)
    fw.setOutputFormat('gpkg')
    fw.setCreateOptions(["RASTER_TABLE=" + str(tableName), 'APPEND_SUBDATASET=YES'])

    pipe = QgsRasterPipe()
    if pipe.set(provider.clone()) is True:
        projector = QgsRasterProjector()
        projector.setCrs(provider.crs(), provider.crs())
        if pipe.insert(2, projector) is True:
            if fw.writeRaster(pipe, provider.xSize(), provider.ySize(), provider.extent(), provider.crs()) == 0:
                print("ok")
            else:
                print("error")
ds = None

For reading raster layer in GeoPackage:

from qgis.core import QgsRasterLayer

rlayer = QgsRasterLayer('GPKG:' + str(self.projectGpkg) + ':tableName', "layerName")
1

For raster layers, use the GDAL's "Translate (convert format)" algorithm:

import processing

params = { 
    'COPY_SUBDATASETS' : False, 
    'DATA_TYPE' : 0, 
    'EXTRA' : '-co APPEND_SUBDATASET=YES -co RASTER_TABLE=name_of_layer', 
    'INPUT' : layer_to_add, 
    'NODATA' : None, 
    'OPTIONS' : '', 
    'OUTPUT' : 'existing.gpkg', 
    'TARGET_CRS' : None 
}
processing.run("gdal:translate", params)

For vector layers see the answer from @GermánCarrillo.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.