2

I have an existing GeoPackage and want to copy Features from another layer to this one using PyQGIS and execute it inside a QGIS Macro. For that, I have the following code:

from qgis.core import QgsProject, QgsVectorLayer, QgsFeatureRequest, QgsFeature, QgsDefaultValue
project = QgsProject.instance()
for layer in project.mapLayers().values():
 if layer.name() in layer_list_analog and isinstance(layer, QgsVectorLayer):
 # Attribute 'Typ' und 'Projekt' abfragen
 typ = feature['Typ']
 projekt = feature['Projekt']
 # Überprüfen, ob ein entsprechendes Feature im 'Analoge'-Layer vorhanden ist
 request = QgsFeatureRequest()
 request.setFilterExpression(f'"Typ" = \'{typ}\' AND "Projekt" = \'{projekt}\'')
 matching_features = analoge_layer.getFeatures(request)
 if not any(matching_features):
 # Feature ist nicht vorhanden, daher fügen wir es hinzu
 new_feature = QgsFeature(feature)
 new_feature.setFields(analoge_layer.fields())
 # new_feature.setAttributes(feature.attributes())
 fields = {
 'Typ': typ,
 'Projekt': project
 }
 for field in fields.keys():
 field_idx = analoge_layer.fields().indexOf(field)
 analoge_layer.setDefaultValueDefinition(field_idx, QgsDefaultValue(f'\'{fields[field]}\''))
 analoge_layer.dataProvider().addFeature(new_feature)

However, I just can safe the geometry into the GeoPackage, the Attribute Fields are empty.


After @Andre Geo'S comment I changed the code this way, but still, it does not work:

from qgis.core import QgsProject, QgsVectorLayer, QgsFeatureRequest, QgsFeature, QgsDefaultValue
project = QgsProject.instance()
for layer in project.mapLayers().values():
 # Überprüfen, ob der Layer im Exportset ist
 if layer.name() in layer_list_analog and isinstance(layer, QgsVectorLayer):
 # Attribute 'Typ' und 'Projekt' abfragen
 typ = feature['Typ']
 projekt = feature['Projekt']
 # analoge_layer.startEditing()
 # Überprüfen, ob ein entsprechendes Feature im 'Analoge'-Layer vorhanden ist
 request = QgsFeatureRequest()
 request.setFilterExpression(f'"Typ" = \'{typ}\' AND "Projekt" = \'{projekt}\'')
 matching_features = analoge_layer.getFeatures(request)
 analoge_layer.startEditing()
 if not any(matching_features):
 # Feature ist nicht vorhanden, daher fügen wir es hinzu
 new_feature = QgsFeature(analoge_layer.fields())
 # new_feature.setFields()
 new_feature.setGeometry(feature.geometry())
 # new_feature.setAttributes(feature.attributes())
 attributes = feature.attributes()
 output_file_path = r"C:\data.txt"
 fields = {
 'Typ': attributes[2],
 'Projekt': attributes[6]
 }
 with open(output_file_path, 'w') as file:
 file.write(f"{fields}\n")
 for field in fields.keys():
 field_idx = analoge_layer.fields().indexOf(field)
 analoge_layer.setDefaultValueDefinition(field_idx, QgsDefaultValue(f'\'{fields[field]}\''))
 analoge_layer.addFeature(new_feature)
 analoge_layer.updateFeature(new_feature)
 analoge_layer.commitChanges()
asked Aug 5, 2024 at 13:50
2
  • You need to layer.startEditing() and layer.commitChanges() before and after modifying the layer. Or wrap it in edit Commented Aug 6, 2024 at 7:36
  • Thanks for your hint, I added it but it still does not include the attributes. I also tried to use analoge_layer.setAttributes(feature.attributes()) but in this case, it does not even safe the geometry. Commented Aug 6, 2024 at 9:04

1 Answer 1

0

Several definitions seem to be missing from your script like feature and analoge_layer for example which make it harder to replicate.

There are a few problems with your code other than it doesn't work, like this new_feature.setGeometry(feature.geometry()) should not be used because it sets the same geometry object to two features and can and will probably cause errors (sometimes). What you need to do is clone it with new_feature.setGeometry(QgsGeometry(feature.geometry()))

But for copying features what I would do is the following:

from qgis.core import QgsProject, QgsVectorLayer, QgsFeatureRequest, QgsFeature, QgsDefaultValue
project = QgsProject.instance()
for layer in project.mapLayers().values():
 # Überprüfen, ob der Layer im Exportset ist
 if layer.name() in layer_list_analog and isinstance(layer, QgsVectorLayer):
 # Attribute 'Typ' und 'Projekt' abfragen
 typ = feature['Typ']
 projekt = feature['Projekt']
 # analoge_layer.startEditing()
 # Überprüfen, ob ein entsprechendes Feature im 'Analoge'-Layer vorhanden ist
 request = QgsFeatureRequest()
 request.setFilterExpression(f'"Typ" = \'{typ}\' AND "Projekt" = \'{projekt}\'')
 matching_features = analoge_layer.getFeatures(request)
 if not any(matching_features):
 
 # If the fields are differently ordered between layers or they are otherwise different
 new_feature = QgsFeature(analoge_layer.fields())
 field_names = analoge_layer.fields().names()
 for key, value in feature.attributeMap().items():
 if key in field_names:
 new_feature.setAttribute(key, value)
 new_feature.setGeometry(QgsGeometry(feature.geometry()))
 # Or if the fields are exactly the same between layers
 # new_feature = QgsFeature(feature)
 
 with edit(analoge_layer):
 analoge_layer.addFeature(new_feature)
 
answered Aug 7, 2024 at 6:30

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.