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()
1 Answer 1
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)
Explore related questions
See similar questions with these tags.
layer.startEditing()
andlayer.commitChanges()
before and after modifying the layer. Or wrap it in editanaloge_layer.setAttributes(feature.attributes())
but in this case, it does not even safe the geometry.