17

I would like to update one attribute of a feature. However, I don't know to update it using the feature object. I have to use a data provider to update it.

layers = QgsMapLayerRegistry.instance().mapLayersByName('my_line') 
layer = layers[0]
dp = layer.dataProvider()
it = dp.getFeatures()

for i in range(0, dp.featureCount()):
    feat = it.next()
    attrs = { 2 : 30 }
    layer.dataProvider().changeAttributeValues({ feat.id() : attrs })

Can I change the value of an attribute using QgsFeature object?

Moreover, is it possible to loop using an iterator object?

5
  • how can I change values without using the index? I would like to change the values by naming their fieldname. That would be much more comfortable. Thank you very much! Greetings Robert
    – Robert B K
    Commented Jan 5, 2018 at 21:20
  • 1
    Simply use my_index = layer.fieldNameIndex("my_field_name") to get the index. Commented Jan 5, 2018 at 22:18
  • in this case i cant add in the field the string how i can do? Commented Mar 13, 2018 at 13:24
  • If you have a new question, please ask it by clicking the Ask Question button. Include a link to this question if it helps provide context. - From Review
    – Dan C
    Commented Mar 13, 2018 at 13:32
  • Hamed, Welcome to GIS Stack Exchange! Since this question has already been answered, please ask your question as a new, separate question here gis.stackexchange.com/questions/ask.
    – cm1
    Commented Mar 13, 2018 at 13:49

3 Answers 3

35

Answering your two questions:

  1. You can change your feature values from the layer object, no need to access the dataProvider().

  2. Yes, you can use the iterator in a for loop (that's what iterators are for :) ).

Using layer.changeAttributeValue()

changeAttributeValue() is handy when you want to change the value of a single field for your features. For instance, let's see how to modify a single field for selected features:

layers = QgsProject.instance().mapLayersByName('my_line') 
layer = layers[0]  # We assume there is at least 1

field_idx = layer.fields().indexOf('my_field_name')
new_value = 30

with edit(layer):
    for feat_id in layer.selectedFeatureIds():
       layer.changeAttributeValue(feat_id, field_idx, new_value)

Which updates the field value to 30 for selected features.


If you want to update the field value for all features in your layer, do something like this:

with edit(layer):
    for feat in layer.getFeatures():
       layer.changeAttributeValue(feat.id(), field_idx, new_value)

Which updates the field value to 30 for all layer features. See this answer for optimizing the getFeatures() method.

Regarding layer.updateFeature()

Always try to avoid the QgsVectorLayer.updateFeature() method. It's less efficient than changeAttributeValue().

From the docs:

This method needs to query the underlying data provider to fetch the feature with matching QgsFeature::id() on every call. Depending on the underlying data source this can be slow to execute. Consider using the more efficient changeAttributeValue() or changeGeometry() methods instead.

0
10

To update a feature in PyQGIS, you can use the attribute name, as in feature['state'] = 'DONE', instead of the field index. It is much more readable.

layer = iface.activeLayer()
features = layer.getFeatures()

for feature in features:
    if feature['state'] == 'READY':
        with edit(layer):
            feature['state'] = 'DONE'
            layer.updateFeature(feature)

If you prefer to use the field index, you can get it with:

fields = layer.fields()
idx = fields.indexFromName('state')
6

Yes, but you have to know the index of the field:

QgsFeature::setAttribute(int field,const QVariant & attr )  

You can get the fields using QgsFeature::fields and then iterate through them until you find the one you want or QgsFeature::attribute(const QString & name ) to find the field index by name.

The reason for QVariant is that the setAttribute can take Integer, Float, Date and Text types. QgsFeature.attribute(name) returns a variant also of type int if the attribute is found and something else if it can't be found.. be aware of this in your code. A try..except block would be warranted, try to convert to int and except if type is not int.

It is possible that your feature doesn't support this method. Another method that I have employed is QgsVectorLayer::changeAttributeValue:

self.canvas.currentLayer().changeAttributeValue(UpdateFeatureID,FieldToUpdate,self.CurrentWidget.text(),True)

This tells the layer to update a specific feature and specific attribute. In the example case the value comes from a widget.

4
  • I tried feat.setAttribute(1, QVariant(20)) but the system said TypeError: PyQt4.QtCore.QVariant represents a mapped type and cannot be instantiated
    – wannik
    Commented Jun 16, 2014 at 3:09
  • feat.setAttribute(1, 20) is how I've done it before. That is put the value '20' into attribute 1. Commented Jun 16, 2014 at 3:11
  • I tried feat.setAttribute(1, 20) but the values don't change. However, I can print(feat.attributes()[1])
    – wannik
    Commented Jun 16, 2014 at 3:28
  • See edits, perhaps you have to call the QgsVectorLayer.changeAttributeValue which should use the driver to make the changes. Commented Jun 16, 2014 at 3:38

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.