1

I am working on a script that runs a model and then appends the result to a spatialite layer. The model runs zonal statistics using 4 different rasters and appends them to the attribute table of a vector polygon layer with a single feature. The attribute table of the model output (habitatModel) looks as follows:

id  | hs90_mean | hs14_mean | ls90_mean | ls14_mean
----+-----------+-----------+-----------+----------
 1  | 46.043816 | 44.009554 | 47.859847 | 45.308090

The type of the id field is integer, and I need to replace that with a string identifier, so I load the layer as a QgsVectorLayer, add a genspec field and delete the id field:

habitatModelLayer = QgsVectorLayer(habitatModel,genspec,'ogr')
habitatModelLayer.dataProvider().addAttributes([QgsField("genspec", QVariant.String)])
habitatModelLayer.dataProvider().deleteAttributes([habitatModelLayer.fields().lookupField('id')])
habitatModelLayer.updateFields()

Then I try to update the attribute values using dataprovider().changeAttributeValues():

iterator = habitatModelLayer.getFeatures(QgsFeatureRequest().setFilterFid(0))
feature = next(iterator)
attrs = {habitatModelLayer.fields().lookupField('genspec'):'2759-9',
    habitatModelLayer.fields().lookupField('hs90_mean'):feature['hs90_mean'],
    habitatModelLayer.fields().lookupField('ls90_mean'):feature['ls90_mean'],
    habitatModelLayer.fields().lookupField('hs14_mean'):feature['hs14_mean'],
    habitatModelLayer.fields().lookupField('ls14_mean'):feature['ls14_mean']}
habitatModelLayer.dataProvider().changeAttributeValues({0:attrs})
habitatModelLayer.commitChanges()

I then add the layer to the spatialite file database using qgis:importintospatialite:

processing.run("qgis:importintospatialite", {
    'INPUT':habitatModelLayer,
    'DATABASE':spatialiteLayer,
    'TABLENAME':'models',
    'PRIMARY_KEY':'genspec',
    'GEOMETRY_COLUMN':'geom',
    'ENCODING':'UTF-8',
    'OVERWRITE':True,
    'CREATEINDEX':True,
    'LOWERCASE_NAMES':False,
    'DROP_STRING_LENGTH':False,
    'FORCE_SINGLEPART':False
})

The resulting layer has the correct values for the zonal stats, but the genspec field is empty. Any idea why this would be?

A strange side-note is that when the habitatModel layer is added to the canvas as a result of the script, it initially still shows the new attributes squashed into the old fields (and trying to conform to the old types):

id  | hs90_mean | hs14_mean | ls90_mean | ls14_mean
----+-----------+-----------+-----------+----------
 46 | 44.009554 | 47.859847 | 45.308090 | 2795

but after a few minutes the attribute table corrects itself:

 hs90_mean | hs14_mean | ls90_mean | ls14_mean | genspec
-----------+-----------+-----------+-----------+---------
 46.043816 | 44.009554 | 47.859847 | 45.308090 | 2759-9

Is there some kind of buffer that needs to be flushed before I write to the spatialite database?

1

I think there was an issue somehow because the order of the fields changed. I ended up taking a different approach. Since I'm only really interested in the feature, not the layer, I created a copy of the feature and used the dataProvider() for the spatialite layer to add the feature there. The working code is as follows:

    # fetch feature and map attributes for destination layer
    habitatModelLayer = QgsVectorLayer(habitatModel,genspec,'ogr')
    iterator = habitatModelLayer.getFeatures(QgsFeatureRequest().setFilterFid(0))
    feature = next(iterator)
    spatialiteFeature = QgsFeature(feature)        # make a copy        
    spatialiteFields = spatialiteLayer.fields()
    spatialiteFeature.setFields(spatialiteFields)  # replace source with destination fields
    for f in spatialiteFeature.fields().names():
        if f == 'genspec':
            spatialiteFeature[f] = genspec      # in destination but not source layer
        else:
            spatialiteFeature[f] = feature[f]   # map destination to source attributes

    # first delete any existing features with this id (genspec)
    spatialiteLayer.startEditing()              # deleteFeature requires an active edit session
    filter = QgsExpression.createFieldEqualityExpression('genspec',genspec)
    request = QgsFeatureRequest().setFilterExpression(filter)
    request.setSubsetOfAttributes([])
    request.setFlags(QgsFeatureRequest.NoGeometry)
    for f in spatialiteLayer.getFeatures(request):
        feedback.pushInfo(f"Found existing model with genspec {genspec}. Replacing with new model.")
        spatialiteLayer.deleteFeature(f.id())
    spatialiteLayer.commitChanges()

    # add feature to destination layer
    if not spatialiteLayer.dataProvider().addFeatures([spatialiteFeature]):
        feedback.pushError(f"Error adding model for taxon {genspec} to spatialite:") 
        for f in spatialiteFeature.fields().names():
            feedback.pushInfo(f"{f}: {spatialiteFeature.attributes()[spatialiteFeature.fields().lookupField(f)]}")

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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