4

So I'm trying to convert code from ArcGIS to QGIS. The part I am at right now is converting:

lst_fields = ["full_id", "osm_id", "osm_type", "boundary", "is_in", "leisure", "name", "type", "landuse"]
with arcpy.da.UpdateCursor(urh, lst_fields) as cursor:
    for row in cursor:
         ...

However, with QGIS I have to instead use:

with edit(vector_layer):
    for row in vector_layer.getFeatures(request):

I did not find a way to get only the fields specified in the list apart from doing another for loop and doing this and then storing the values in another list:

row.attributes()[row.fields().indexFromName('boundary')]

The code I have right now is:

lst_fields = ["full_id", "osm_id", "osm_type", "boundary", "is_in", "leisure", "name", "type", "landuse"]
vector_layer = QgsVectorLayer(repertoire+'\\protected_areas.shp','ogr')
request = QgsFeatureRequest().setSubsetOfAttributes(lst_fields, vector_layer.fields())

with edit(vector_layer):
    for row in vector_layer.getFeatures(request):
        print(lst_fields)
        print(row.fields().names())

The first print gives this:

['full_id', 'osm_id', 'osm_type', 'boundary', 'is_in', 'leisure', 'name', 'type', 'landuse']

The second print gives this:

['full_id', 'osm_id', 'osm_type', 'boundary', 'is_in', 'leisure', 'name', 'type', 'wikidata', 'wikipedia', 'landuse', 'name_de', 'sagns_id', 'website']

I thought the request would make it so the two prints would give the same result. I will say what my question is again just in case it wasn't clear:

Is there a way to only get the fields specified in the list like it was possible in arcGIS without the need of another for loop that would save the value of 1 field at a time.

1
  • 1
    Right, it's a bit counter intuitive. But, it works in this way: you specify a list of attributes you want to get values from, and then getFeatures(request) goes to the data provider and asks for those specific fields, optimizing the query performance. In the response, fields() will still give you all field names, but if you print feature.attributes() you'll only get values for those from your list (the rest will be None). Now, using your initial list you could ask feature values like this: for fieldname in my_list: print(feature[fieldname]). May 11, 2020 at 20:56

1 Answer 1

3

German pointed out already that QgsFeatureRequest.setSubsetOfAttributes([li_required_idx]) returns None for any attribute not in li_required_idx. With some list comprehension it is possible to get li_attr equal to li_fields in the following code:

lyr = iface.activeLayer()
li_required_fields = ["POP_EST", "NAME_RU", "POP_DENSITY"]
request = QgsFeatureRequest().setSubsetOfAttributes(li_required_fields, lyr.fields())

for f in lyr.getFeatures(request):
    li_attr = [attr for attr in f.attributes() if attr is not None]
    print(li_attr)

Now all request attributes (li_required_fields) are in (li_attr). If you want to get 1 attribute at a time, then using the f[required_attr] is probably the best approach as German suggested.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.