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.

Matt
  • 16,843
  • 3
  • 21
  • 52

2 Answers2

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.

etrimaille
  • 7,240
  • 34
  • 47
  • Ah yes, of course. What a silly oversight! I am not referencing the layer in the layers panel at all.. thank you. – Matt Mar 19 '22 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 Mar 23 '22 at 12:01
1

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

QgsProject.instance().reloadAllLayers()
Matt
  • 16,843
  • 3
  • 21
  • 52