2

I am developing a small plugin in which I would like to create a dropdown menu that would enable the user to choose among a list of polygons (stored in a PostGIS database) according to their names.

Here is a sample of what I tried so far :

self.sql1 = '(SELECT * FROM schema.layer1 WHERE layer1.name =' + str(dlg.comboBox.currentText()) + ')'
self.uri.setDataSource('', self.sql1, 'geom', '', 'id')
self.layer1 = QgsVectorLayer(self.uri.uri(), "layer1", "postgres")


if self.layer1.isValid:
    self.Project.addMapLayer(self.layer1)
else:
    print('Chargement de la couche: echec !')

# Créer un dossier dont le nom est un attribut du champs 'name' de la couche active

idx = self.interface.activeLayer().fields().indexFromName('name')

self.path = "C:/folder/name_layer1_"

for feat in self.interface.activeLayer().getFeatures():
    self.attrs = feat.attributes()
    if os.path.exists(self.path + self.attrs[idx]) == False :
        os.makedirs(self.path + self.attrs[idx])

                # Sauvegarde du shp dans le dossier créé

QgsVectorFileWriter.writeAsVectorFormat(self.layer1, self.path + self.attrs[idx] + '/layer1.shp', "utf-8",self.layer1.crs(), "ESRI Shapefile")

Unfortunately I get a warning I can't solve:

QgsVectorFileWriter.writeAsVectorFormat(self.layer1, self.path + self.attrs[idx] + '/layer1.shp', "utf-8",self.layer1.crs(), "ESRI Shapefile") AttributeError: 'Test1Plugin' object has no attribute 'attrs'

What I don't understand is that I don't face any problem when I don't add a combobox :

self.sql1 = '(SELECT * FROM schemaA.layer1 WHERE layer1.name = \'D27-16\')'
self.uri.setDataSource('',self.sql1,'geom','','id')
self.layer1 = QgsVectorLayer(self.uri.uri(), "layer1", "postgres")

or when I use the primary key of layer1 in the comboBox :

self.sql1 = '(SELECT * FROM schema.layer1 WHERE layer1.id=' + str(dlg.comboBox.currentText()) + ')'
self.uri.setDataSource('', self.sql1, 'geom', '', 'id')
self.layer1 = QgsVectorLayer(self.uri.uri(), "layer1", "postgres")

Does someone see what I'm missing?

4
  • Is it because of that: gis.stackexchange.com/a/112413/162856 ? – wanderzen Jan 6 at 14:01
  • 3
    Yes, when you have an id, your string returns layer1.id = 5 for example, this is correct. When it is a name, it's characters, so, you must quoting the name so layer1.name = \'' + your_dialog + '\'' will return layer1.name = 'D27-16'. – J. Monticolo Jan 6 at 14:02
  • 1
    Be sure self.layer1.featureCount() is not zero. – Kadir Şahbaz Jan 6 at 14:19
  • 2
    Again, thank you very much J.Monticolo ! It was driving me crazy !! You can post your comment as an answer ! – wanderzen Jan 6 at 14:19
2

It's a missing quotes error.

A good advice to debug queries build like this or all strings build with variables, it's just to print the result to see if it's good.

So, what if we debug the good one ?

print(
    '(SELECT * FROM schema.layer1 WHERE layer1.id=' + str(dlg.comboBox.currentText()) + ')'
)

# Note that a more Pythonic way to write this is :
# for Python < 3.6
combo_text = str(dlg.comboBox.currentText())
"(SELECT * FROM schema.layer1 WHERE layer1.id={0})".format(combo_text)
# for Python >= 3.6
f"(SELECT * FROM schema.layer1 WHERE layer1.id={combo_text})"

it will print :

>>> print(...)
(SELECT * FROM schema.layer1 WHERE layer1.id=5)

and if we try it under a database, it works.

But if we debug the problematic one :

print(
    '(SELECT * FROM schemaA.layer1 WHERE layer1.name = \'D27-16\')'
)
# for Python < 3.6
lyr_name = "D27-16"
"(SELECT * FROM schema.layer1 WHERE layer1.name = {0})".format(lyr_name)
# for Python >= 3.6
f"(SELECT * FROM schema.layer1 WHERE layer1.name = {lyr_name})"

it will print :

(SELECT * FROM schema.layer1 WHERE layer1.name = D27-16)

and if we try it in a DB, it will cause an error. Why ? Quotes. If we had used the Pythonic string format, we would have had more chance to see this error.

Solution

So, the correct code is :

lyr_name = "D27-16"
self.sql1 = "(SELECT * FROM schema.layer1 WHERE layer1.name = '{0}')".format(lyr_name)
# or for Python >= 3.6
self.sql1 = f"(SELECT * FROM schema.layer1 WHERE layer1.name = '{lyr_name}')"

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.