1

QGIS 3.24.0. I am adding a field to my attribute table using PyQGIS and populating the rows with a URL. The layer in question is a GeoPackage Point layer.

The attribute is added to the dataProvider and is populated as intended, but the field does not show in the attribute table until I click the Reload the table button.

How do I reload the table using PyQGIS?

I have tried lyr.dataProvider().reloadData() and lyr.dataProvider().forceReload() (found in a comment in this answer). But the underlying data in the provider is correct and these have no effect on the attribute table.

p = QgsProject.instance()
lyr = QgsVectorLayer(r'path_to_my_gpkg\data.gpkg|layername=query_point', 'query_point')

# get the features
feats = list(lyr.getFeatures())

# create the field if it does not yet exist
field_name = 'url'
if field_name not in lyr.fields().names():
    lyr.dataProvider().addAttributes([QgsField(field_name, QVariant.String)])
    lyr.updateFields()
    # lyr.commitChanges()  # no effect
    # lyr.dataProvider().forceReload() # no effect

# get the field index of the new field
fields = lyr.fields()
idx = fields.indexFromName(field_name)

for f in feats:
    url =  'my/pseudo/url'
    
    lyr.startEditing()
    
    # update the feature attribute at the index of the new field
    lyr.changeAttributeValue(f.id(), idx, url)

    # lyr.updateFeature(f) # no effect
    
    lyr.commitChanges()

    # lyr.dataProvider().reloadData() # no effect

enter image description here

After some experimentation:

Adding iface.showAttributeTable(lyr) to the last line of the script opens a new instance of the attribute table with the field showing. Despite this, an attribute table opened via right-clicking the layer name still only shows 2 fields until it is reloaded using the button.

2 Answers 2

3

In your script, you are editing the file directly by creating a new internal object QgsVectorLayer, not the layer in your legend.

query_point is a "QgsVectorLayer", but lyr is another "QgsVectorLayer" object. Even if they are pointing to the same underlying datasource, it's two different objects. So then, when you are trying to force reloading the dataprovider, you are on the pyqgis object, you are not on the one loaded in your legend. It's TWO different layers for the QGIS point of view.

I suggest you to get the same QgsVectorLayer object from the legend. For instance :

lyr = p.mapLayersByName('query_point')[0].

At least at the end, when you want to reload the dataprovider, you should call the function using the layer loaded in the legend, not created in PyQGIS.

If you want to see it's two different layers :

layer_1 = QgsVectorLayer(r'path_to_my_gpkg\data.gpkg|layername=query_point', 'query_point_in_pyqgis')
print("layer_1")
print(layer_1.id())
print(layer_1.name())
layer_2 = p.mapLayersByName('query_point')[0]
print("layer_2")
print(layer_2.id())
print(layer_2.name())

It's two different layer ID.

2
  • Ah yes, of course. What a silly oversight! I am not referencing the layer in the layers panel at all.. thank you.
    – Matt
    Commented Mar 19, 2022 at 14:19
  • While your answer addresses why the issue occured, I have made and accepted a different answer as it directly solves my question "How do I reload the table using PyQGIS?"
    – Matt
    Commented Mar 23, 2022 at 12:01
1

As per this answer, the attribute table can be refreshed using:

QgsProject.instance().reloadAllLayers()

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.