QGIS Python – How to Change Attributes

fields-attributespythonqgis-2

I have this piece of code which I would like to use for inserting values into a column. It does not throw an error, the changes are not written to the source (shapefile).

from qgis.utils import iface
from PyQt4.QtCore import *

layers = iface.legendInterface().layers()

for layer in layers:
    name = layer.name()
    if name.endswith('x'):
        provider = layer.dataProvider()   
        features = provider.getFeatures()
        for feature in features:
            feature.setAttribute('attr', 'a')

I understood there are two ways of editing data sources: directly with dataProvider or with edit buffer. If I got it right, it shouldn't be necessary to call commit action when using dataProvider.

I'm using QGIS 2.2 Valmiera.

Best Answer

You are right, that you don't need to call commit if you work on the dataProvider directly. However, this will also commit every update immediately, leading to more I/O overhead (often decreased performance) and poor transaction handling. This is to say, the method works, but use it carefully. I have added another method below which is better suited in most cases.

The problem in the code is, that you are only setting the attribute on the feature in memory and don't tell the provider, that this feature changed. Instead, try the following code. It buffers all updates in the updateMap and then executes it in one go at the end, therefore allowing batch updates (useful e.g. on slow networks). Another possibility would be to issue updateAttributeValue directly in the loop.

from qgis.utils import iface
from PyQt4.QtCore import *

layers = iface.legendInterface().layers()

for layer in layers:
    name = layer.name()
    if name.endswith('x'):
        provider = layer.dataProvider()
        updateMap = {}
        fieldIdx = provider.fields().indexFromName( 'attr' )
        features = provider.getFeatures()
        for feature in features:
            updateMap[feature.id()] = { fieldIdx: 'a' }

        provider.changeAttributeValues( updateMap )

The generally recommended way:

with edit(layer):
    for feature in layer.getFeatures():
        feature['fieldName'] = newValue
        layer.updateFeature(feature)

http://qgis.org/api/2.2/classQgsVectorDataProvider.html#a99a5d01c33c1cadb7ae9209b68cd8743