I want to create empty GeoPackage layers with a defined schema. This seems to just work with Fiona regardless of whether I have spatial or non-spatial layers:
def create_blank_gpkg_layer(
gpkg: Path, layer_name: str, crs: dict, schema: dict
) -> dict:
"""
Thin wrapper around fiona.open to create an empty layer in a geopackage
If the geopackage doesn't exist it is created.
Any existing geopackage or layer that shares the same names are overwritten
"""
gpkg.parent.mkdir(exist_ok=True, parents=True)
with fiona.open(
gpkg,
"w",
driver="GPKG",
crs=crs,
layer=layer_name,
schema=schema,
overwrite=True,
) as new_layer:
meta = new_layer.meta
print(f"{layer_name} created in {gpkg}")
return meta
wgs_crs = from_epsg(4326)
poly_schema = {
"properties": OrderedDict([("name":"str"),("code":"int")]),
"geometry": "Polygon"
}
not_spatial_schema = {"properties": OrderedDict([("name":"str"),("code":"int")])}
create_blank_gpkg_layer(gpkg, layer_name=poly, crs=crs, schema=poly_schema)
create_blank_gpkg_layer(gpkg, layer_name=not_spatial, crs=crs, schema=not_spatial_schema)
This is fine, but I'd rather not have fiona
as a dependency if the capability is already within QGIS - which is where the GeoPackages will end up, and I will have seperate code to configure symbology etc.
So I'd like to do the same using the PyQGIS QgsVectorFileWriter
or whatever is most appropriate.
I've managed to make a workaround that creates a memory layer and then writes it, but I feel like there is probably a more 'idiomatic' way of solving this, as I then have to get the layer I've created in the GeoPackage (the one I actually want) and add it to the map.
# Layers that have a geometry
foo_layer = QgsVectorLayer("Point?crs=epsg:4326&field=name:string", "foo layer", "memory")
params={'INPUT': foo_layer, 'OPTIONS':'-update -nln foo','OUTPUT': '/tmp/temp_gpkg.gpkg'}
processing.run("gdal:convertformat", params)
# Layers with no geometry
bar_layer = QgsVectorLayer('None', 'bar', 'memory')
bar_layer.startEditing()
bar_layer.addAttribute(QgsField('name',QVariant.String))
bar_layer.commitChanges()
params={'INPUT': bar_layer,'OPTIONS':'-update -nln bar','OUTPUT': '/tmp/temp_gpkg.gpkg'}
processing.run("gdal:convertformat", params)
ogrinfo -sql "create table foo (attr1 text, attr2 int)" test.gpkg
. But if your aim is to create a table with a geometry column then it gets more complicated.