2

I'm building my first script purposed to :

  1. Create fields if they doesn't already exist
  2. Fill value in this fields

The code works, but I have to perform it 2 times when the case requierts to Add Fields (when they did not already exist). In fact, when I launch the code the first time, it adds fields missing but it doesn't fill fields and I get an error message :

The fields -1 of the feature n°... doesn't exist.

Fields are now built and if I re launch the script, I do not get error anymore and it fills the fields.

How can I fix my script to enable it to perform both parts at the first launch?

from PIL import Image
from PIL.ExifTags import TAGS, GPSTAGS
from xml.etree import ElementTree as ET


layer = iface.activeLayer()
dpr = layer.dataProvider()

apr_ind = layer.fields().indexFromName("apr")


# add fields
fields_arr =  [("apr", QVariant.Double)]
flds = [QgsField(i[0], i[1]) for i in fields_arr if i[0] not in [fld.name() for fld in layer.fields()]]
layer.dataProvider().addAttributes(flds)
layer.updateFields()
# field update
layer.updateFields()
layer.startEditing()
for feature in layer.getFeatures():
    file_path = feature["Path"] 
    print(file_path)
    img = Image.open(file_path)
    exif = { TAGS[k]: v for k, v in img._getexif().items() if k in TAGS }
    with open(file_path, "rb") as f:
        s = str(f.read())
    start = s.find('<x:xmpmeta')
    end   = s.find('</x:xmpmeta')
    xmp   = s[start:end+12].replace("\\n","\n")
    tree  = ET.XML(xmp)
    apr = exif["FNumber"][0]/exif["FNumber"][1]

    dpr.changeAttributeValues({ feature.id():{apr_ind: apr }})
layer.commitChanges()
print("COMPLETED") 
3
  • 1
    I think you should look up field indexes after creating fields (instead of before). – Ben W Dec 18 '19 at 11:50
  • at the moment my process is : adding field -> updatefields -> startediting -> change attribute value -> comit changes. Do you suggest me to put an index function between update and editing? – zlikotp Dec 18 '19 at 11:52
  • 1
    Yes, precisely! Because if field index doesn't exist, changeAttributeValues() method won't work. – Ben W Dec 18 '19 at 12:02
2

The following script allows you to check the existence of a field and create it if it does not exist. To do this, I declare as an entry a list of the desired fields.

I add a numeric field but for example if the fields do not all have the same type, you can imagine a list of the desired fields by type and thus make several loops.

layer = iface.activeLayer() 
dpr = layer.dataProvider()

# Fields you want
fields = ["test","test_1","test_2","test_3","test_4"]

# Loop on the fields you want
for field in fields : 

    # Index of the field 
    verify_index = layer.fields().indexFromName(field)

    # The field does not exist
    if verify_index == -1 :
        print("The field " + field + " does not exist ! we will create it")
        # add field
        dpr.addAttributes([QgsField(field, QVariant.Double)])
    else : 
        print("The field " + field + " already exists ! No creation")

    # field update
    layer.updateFields()
2
  • I could also use only one loop but a 2 dimensional array right? – zlikotp Dec 18 '19 at 12:01
  • Yes, you can try! – Vincent Bré Dec 18 '19 at 12:55
0

The issue here is that you are looking up field indexes at the beginning of the script (before creating them). For example, if the field "apr" does not yet exist, the indexFromName() method will return -1 and this will be stored in your apr_ind variable.

The next part of your code checks to see if a field with that name exists and, if it doesn't, creates it. However, in the last part of your code- when you call:

dpr.changeAttributeValues({ feature.id():{apr_ind: apr }})

you are passing the apr_ind variable, which is still storing the value -1, because it has not been updated and does not know that the field has now been created.

To fix this issue you should move any lines which look up field indexes so that they are after the line:

layer.updateFields()

This will take into account the newly created fields and will successfully look up and store their indexes.

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.