TransWikia.com

QGIS 3.10.8 Add features and attributes to exisiting layer using python

Geographic Information Systems Asked on December 8, 2021

Is there a way to add features from one layer to another while matching attribute names using Python?

Using QGIS 3.10.8
I am trying to add features to an existing layer. I have been using the code below to add the features, this code however does not match the attribute names and populates the added features in the order of the layer I am obtaining features from.

For example: If I have N-1 attributes in the layer I am obtaining the features from, the data will add features, but will add "NULL" to the last attribute columns, while the attributes with "NULL" should have been somewhere else, illustrated in the picture at the bottom.

Is there a way to ensure that features get added to the correct attribute?

layer = QgsVectorLayer(Out, "Out","ogr")
feats = []
for feat in Inn.getFeatures():
    feats.append(feat)
layer.startEditing()
dp = layer.dataProvider()
dp.addFeatures(feats)
layer.commitChanges()

Illustration of problem

One Answer

I wrote this script a while ago which should do what you want. The key is setting up your field mapping in nested lists. You can use this approach to match fields with completely different names and have control over matching which attributes are copied to which field in the target layer. However, in your case, it will ensure that 'Att2' will be copied to 'Att2', 'Att3' to 'Att3' etc. If you have an 'Att1' field in your target layer, it will be either empty or Null for the copied feature. You will need to change the layer names in the script to match your source and target layer names.

project = QgsProject().instance()
# Set up field mapping in lists below e.g. ['Layer A field name', 'Layer B field name']
fld_map = [['Att2', 'Att2'],
            ['Att3', 'Att3']]

layer_1 = project.mapLayersByName('Layer_A')[0] # change 'Layer A' to the name of your source layer
L1_feats = [f for f in layer_1.getFeatures()]

layer_2 = project.mapLayersByName('Layer_B')[0] # change 'Layer B' to the name of your target layer
pr_2 = layer_2.dataProvider()
layer_2.startEditing()
for feat in L1_feats:
    atts = {}
    for item in fld_map:
        atts[layer_2.fields().lookupField(item[1])]= feat.attribute(layer_1.fields().lookupField(item[0]))
    L2_feat = QgsFeature()
    L2_feat.setGeometry(feat.geometry())
    pr_2.addFeature(L2_feat)
    pr_2.changeAttributeValues({L2_feat.id(): atts})
layer_2.commitChanges()
layer_2.updateExtents()

I actually started implementing this in a plugin but got sidetracked and never finished it off. I'm still intending to finish it when I get a chance and upload it to the repository.

Answered by Ben W on December 8, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP