1

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

1
  • Several ways of doing so. Perhaps the easiest is doing it in 2 lines: iface.copySelectionToClipboard(source_layer) iface.pasteFromClipboard(target_layer). Target layer should have the edit session open. Jul 23, 2020 at 12:38

1 Answer 1

2

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.

2

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.