I am trying to use Python for QGIS to add values to new fields in an attribute table based on existing fields and values in a lookup table.

Attribute table I wish to modify (with example rows):

farm      | ref_1 | ref_2 | newField_1 | newField_2
Macdonald | seeds | veg   | <Null>     | <Null>
Fred      | seeds | fruit | <Null>     | <Null>
Bob       | seeds | fruit | <Null>     | <Null>

Lookup table:

ref_1, ref_2, lookup_1, lookup_2
seeds, fruit, 13, 4
seeds, veg, 10, 3

Assuming newFields 1 & 2 have been added to the attribute table, my code is as follows:

aLayer =  qgis.utils.iface.activeLayer()
provider = aLayer.dataProvider()

lookup_table = np.loadtxt(r'filepath\myfile.csv',dtype=str,delimiter=',',skiprows=1)

for feature in aLayer.getFeatures():
    for i in lookup_table:
        if i[0] == feature['ref_1'] and i[1] == feature['ref_2']:
            provider.changeAttributeValues({feature.id() : {provider.fieldNameMap()['newField_1'] : i[2]}})
            provider.changeAttributeValues({feature.id() : {provider.fieldNameMap()['newField_2'] : i[3]}})

After running the code, the newFields 1 & 2 remain null.

Referring to Setting feature attribute by name via QGIS python api? I can get provider.changeAttributeValues() to work based off of fields within the same table (e.g., changing newField_1's value to that of farm); however, if I reference a lookup table, newFields 1 & 2 remain null.

  • When you are describing a problem, it often helps to say what happened instead of what you expected. In this case "it fails" doesn't actually say what happens - does it exit, does the lookup throw an exception, or something else? You can easily edit your question (just click edit below the question) to add this important information.
    – BradHards
    May 14 '15 at 21:12
  • If your lookup table is | delimited but you load it using ',' then it cannot work.
    – underdark
    May 14 '15 at 21:29
  • Thanks Brad - fixed. And underdark, it was formatted with | for ease of reading; the file is comma-separated. Thanks for the clarification. May 14 '15 at 21:59

Probably is related... but you are mixing QgsVectorLayer commit with QgsVectorDataProvider methods. You have to avoid mixing because they work on different workflows!

using dataprovider you write directly on the file using dataprovider interface... and you write it every updateFeature (well could be managed a cache depending on provider... but it's leaved to provider)

using aLayer.startEditing and commitChanges you are using QgsVectorLayer interface that manage Undo/redo with a QgsEditingBuffer... during commmit, the vector layer interface with dataprovider writes (and optimize) changes available in the editing buffer.

probably the commit from layer lever interfere with the changes already done with provider... overwriting them (the layer is unchanghed in the memory cache... but only in the file thanks to provider)

possible solution

1) remove startEditing and commit and use only dataProvider 2) remove dataprovider methods and use qgsvectorlayer method to modifye features... depending if you want a rollback in case of errers, it's more safe using this method.


  • Thanks, this worked! I removed startEditing and commitChanges and the fields were filled correctly. I'd like to try using the qgsvectorlayer method but can't find a specific example of the syntax. I assume this is what you're talking about but don't know how it should actually look in my code. Again, thank you very much:) May 15 '15 at 22:23
  • method name in the class QgsVectotrLayer (see API documentation) are really similar. The only difference is that with QgsVectorLayer you can only modify block of features instead of single feature per time.... try to read API you'll find it really intuitive. ant the guide is here: docs.qgis.org/testing/en/docs/pyqgis_developer_cookbook/… May 17 '15 at 12:16

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.