1

i want to change attributes values in a memory layer.

I already asked a similar question but i'm re-stuck on the problem and don't find any solution to this basic need.

Here is what i'm doing so far :

from PyQt4.QtCore import *
from PyQt4.QtGui import * 
vl_r=QgsVectorLayer('Polygon?crs=epsg:2154','population','memory')
pro_r = vl_r.dataProvider()
pro_r.addAttributes([QgsField("name", QVariant.String)])
pro_r.addAttributes([QgsField("pop", QVariant.Int)])
vl_r.updateFields()
QgsMapLayerRegistry.instance().addMapLayer(vl_r)
fet = QgsFeature()
dummy=pro_r.addFeatures([fet])
print(pro_r.capabilitiesString())
attrib={0:'hell',1:666}
dummy=vl_r.dataProvider().changeAttributeValues({fet.id():attrib})
print('Change values : ' + str(dummy))

The value returned by 'dummy' is always True but i never see any change in the attributes table.

When i use a 'normal' layer (stored on disk) the change is made and is immediately visible without any additional command.

What could i be missing ? My code is so simple that i can't see what i forgot ...

Could anybody give me a working sample of attributes change in a memory Layer ?

underdark
84.9k22 gold badges237 silver badges418 bronze badges
asked Nov 16, 2015 at 20:37
5
  • did you try vl_r.changeAttributeValues() ( i.e. without dataProvider() )? You need to call vl_r.startEditing() first. Commented Nov 16, 2015 at 20:43
  • @Matthias Kuhn U mean vl_r.changeAttributeValue() i suppose ? i never find the right syntax ... i tried vl_r.changeAttributeValue(fet.id(),0,'hell') after a vl_r.startEditing (and a vl_r.commitChanges()) but i don't see any change ... fet.setAttributes(['xxx',888]) works for setting the attributes but when it comes to changing attributes values i never find the right solution ... And why wouldn't the first syntax (using the provider) work ? Commented Nov 16, 2015 at 21:48
  • I wrote about it in the last section here: opengis.ch/2015/04/29/… In short, when you change something directly on the provider, no notifications are emitted. You can also vl_r.updateFeature(fet) if you have a changed feature. Commented Nov 17, 2015 at 8:45
  • @Matthias Kuhn sorry Matthias, i read your article but i didn't find how it was related to my question ... maybe i'm too dumb ... still searching a solution ... i also tried updateFeature but didn't get more result ... Commented Nov 19, 2015 at 8:25
  • Only the last paragraph "Working with the provider" is slightly related (and not really obvious), I meant to link this one instead: opengis.ch/2015/08/12/with-edit-layer look for where it says "Avoid using the dataProvider() methods!". Quote: "They do not emit internal signals for map redraws and other refreshes of the user interface" [...] like the attribute table. Commented Nov 19, 2015 at 8:37

2 Answers 2

3

There are basically two problems with the script you posted.

  1. The feature's attributes are not initialized. So the feature itself does not have any attributes (although the provider has). With other providers this would be less of a problem since when saved and retrieved, new features get created, but the memory provider saves the feature as they are.
  2. The feature which you are updating is the one you created and does not yet have an id. The id is generated in the provider when saved. So before changing anything you have to retrieve the feature again with the generated id.

Below the required changes to your script:

from PyQt4.QtCore import *
from PyQt4.QtGui import * 
vl_r=QgsVectorLayer('Polygon?crs=epsg:2154','population','memory')
pro_r = vl_r.dataProvider()
pro_r.addAttributes([QgsField("name", QVariant.String)])
pro_r.addAttributes([QgsField("pop", QVariant.Int)])
vl_r.updateFields()
QgsMapLayerRegistry.instance().addMapLayer(vl_r)
fet = QgsFeature(vl_r.fields())
# Initialize the feature with 2 attributes. You can make this more generic by using layer information instead of a hardcoded number.
dummy=pro_r.addFeatures([fet])
print(pro_r.capabilitiesString())
attrib={0:'hell',1:666}
# Get the (one and only) feature to have an id to work with
fet = vl_r.getFeatures().next()
dummy=vl_r.dataProvider().changeAttributeValues({fet.id():attrib})
print('Change values : ' + str(dummy))
answered Nov 20, 2015 at 17:33
1
  • Thanks for time spent in answering Matthias ... ! All this remain a bit subtle for me but i will make some other experiments ... Commented Dec 1, 2015 at 17:17
1

Try with:

attrib={0:'hell',1:str(666)}

For me the second attribute passes only with the str(), even if the QgsField is integer... I think there is a bug with changeAttributeValues() with multiple attributes.

answered Oct 4, 2016 at 18:29

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.