def test_joined_layers_conversion(self): v1 = QgsVectorLayer("Point?field=id:integer&field=b_id:integer&field=c_id:integer&field=name:string", "A", "memory") self.assertEqual(v1.isValid(), True) v2 = QgsVectorLayer("Point?field=id:integer&field=bname:string&field=bfield:integer", "B", "memory") self.assertEqual(v2.isValid(), True) v3 = QgsVectorLayer("Point?field=id:integer&field=cname:string", "C", "memory") self.assertEqual(v3.isValid(), True) QgsProject.instance().addMapLayers([v1, v2, v3]) joinInfo = QgsVectorLayerJoinInfo() joinInfo.setTargetFieldName("b_id") joinInfo.setJoinLayer(v2) joinInfo.setJoinFieldName("id") #joinInfo.setPrefix("B_") v1.addJoin(joinInfo) self.assertEqual(len(v1.fields()), 6) df = QgsVirtualLayerDefinitionUtils.fromJoinedLayer(v1) self.assertEqual(df.query(), 'SELECT t.rowid AS uid, t.id, t.b_id, t.c_id, t.name, j1.bname AS B_bname, j1.bfield AS B_bfield FROM {} AS t LEFT JOIN {} AS j1 ON t."b_id"=j1."id"'.format(v1.id(), v2.id())) # with a field subset v1.removeJoin(v2.id()) joinInfo.setJoinFieldNamesSubset(["bname"]) v1.addJoin(joinInfo) self.assertEqual(len(v1.fields()), 5) df = QgsVirtualLayerDefinitionUtils.fromJoinedLayer(v1) self.assertEqual(df.query(), 'SELECT t.rowid AS uid, t.id, t.b_id, t.c_id, t.name, j1.bname AS B_bname FROM {} AS t LEFT JOIN {} AS j1 ON t."b_id"=j1."id"'.format(v1.id(), v2.id())) joinInfo.setJoinFieldNamesSubset(None) # add a table prefix to the join v1.removeJoin(v2.id()) joinInfo.setPrefix("BB_") v1.addJoin(joinInfo) self.assertEqual(len(v1.fields()), 6) df = QgsVirtualLayerDefinitionUtils.fromJoinedLayer(v1) self.assertEqual(df.query(), 'SELECT t.rowid AS uid, t.id, t.b_id, t.c_id, t.name, j1.bname AS BB_bname, j1.bfield AS BB_bfield FROM {} AS t LEFT JOIN {} AS j1 ON t."b_id"=j1."id"'.format(v1.id(), v2.id())) joinInfo.setPrefix("") v1.removeJoin(v2.id()) v1.addJoin(joinInfo) # add another join joinInfo2 = QgsVectorLayerJoinInfo() joinInfo2.setTargetFieldName("c_id") joinInfo2.setJoinLayer(v3) joinInfo2.setJoinFieldName("id") v1.addJoin(joinInfo2) self.assertEqual(len(v1.fields()), 7) df = QgsVirtualLayerDefinitionUtils.fromJoinedLayer(v1) self.assertEqual(df.query(), ('SELECT t.rowid AS uid, t.id, t.b_id, t.c_id, t.name, j1.bname AS B_bname, j1.bfield AS B_bfield, j2.cname AS C_cname FROM {} AS t ' + 'LEFT JOIN {} AS j1 ON t."b_id"=j1."id" ' + 'LEFT JOIN {} AS j2 ON t."c_id"=j2."id"').format(v1.id(), v2.id(), v3.id())) QgsProject.instance().removeMapLayers([v1.id(), v2.id(), v3.id()])
def test_JoinUsingExpression(self): """ test joining a layer using a virtual field """ joinLayer = QgsVectorLayer( "Point?field=x:string&field=y:integer&field=z:integer", "joinlayer", "memory") pr = joinLayer.dataProvider() f1 = QgsFeature() f1.setAttributes(["foo", 246, 321]) f2 = QgsFeature() f2.setAttributes(["bar", 456, 654]) self.assertTrue(pr.addFeatures([f1, f2])) layer = QgsVectorLayer( "Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory") pr = layer.dataProvider() f = QgsFeature() f.setAttributes(["test", 123]) self.assertTrue(pr.addFeatures([f])) layer.addExpressionField('"fldint"*2', QgsField('exp1', QVariant.LongLong)) QgsProject.instance().addMapLayers([layer, joinLayer]) join = QgsVectorLayerJoinInfo() join.setTargetFieldName("exp1") join.setJoinLayer(joinLayer) join.setJoinFieldName("y") join.setUsingMemoryCache(True) layer.addJoin(join) f = QgsFeature() fi = layer.getFeatures() self.assertTrue(fi.nextFeature(f)) attrs = f.attributes() self.assertEqual(attrs[0], "test") self.assertEqual(attrs[1], 123) self.assertEqual(attrs[2], "foo") self.assertEqual(attrs[3], 321) self.assertEqual(attrs[4], 246) self.assertFalse(fi.nextFeature(f)) QgsProject.instance().removeMapLayers([layer.id(), joinLayer.id()])
def buildJoin(self, originalLyr, originalLyrFieldName, joinnedLyr, joinLyrFieldName): """ Builds a join bewteen lyr and joinnedLyr. :param originalLyr: QgsVectorLayer original layer; :param originalLyrFieldName: (str) name of the field; :param joinnedLyr: QgsVectorLayer lyr to be joinned to originalLayer; :param joinLyrFieldName: (str) name of the join field name (usually primary key of joinnedLyr) """ joinObject = QgsVectorLayerJoinInfo() joinObject.setJoinFieldName(joinLyrFieldName) joinObject.setTargetFieldName(originalLyrFieldName) joinObject.setJoinLayer(joinnedLyr) joinObject.setJoinFieldNamesSubset() joinObject.upsertOnEdit(True) #set to enable edit on original lyr joinObject.setCascadedDelete(True) joinObject.setDynamicFormEnabled(True) joinObject.setEditable(True) joinObject.setUsingMemoryCache(True) originalLyr.addJoin(joinObject)
def joinLayer(self, targetlayer, pkfield, sourcelayer, fkfield): """ Join the results of the SQL Server query to the pg layer """ joinInfo = QgsVectorLayerJoinInfo() # Backward compatbility QGIS3=>2 if qversion == 3: joinInfo.setTargetFieldName(pkfield) joinInfo.setJoinLayer(sourcelayer) joinInfo.setJoinFieldName(fkfield) joinInfo.setUsingMemoryCache(True) else: # QGIS 2 joinInfo.targetFieldName = pkfield joinInfo.joinLayerId = sourcelayer.id() joinInfo.joinFieldName = fkfield joinInfo.memoryCache = True targetlayer.addJoin(joinInfo) targetlayer.updateFields() return targetlayer
def complete_fields(self, layer): """Join shapefile to csv and fill in the missing fields based on sub ID""" infoLyr = QgsVectorLayer(f'file:///{str(CSV)}?delimiter=,','classes','delimitedtext') QgsProject.instance().addMapLayer(infoLyr) csv_field = 'Int_SubNum' shp_field = 'HabitatSub' joinObject = QgsVectorLayerJoinInfo() joinObject.setJoinFieldName(csv_field) joinObject.setTargetFieldName(shp_field) joinObject.setJoinLayerId(infoLyr.id()) joinObject.setUsingMemoryCache(True) joinObject.setJoinLayer(infoLyr) layer.addJoin(joinObject) layer.startEditing() ha_areas = [] for feature in layer.getFeatures(): shp_fields = ['HabitatTyp', 'HabitatT_1', 'HabitatS_1', 'MMU_HA'] csv_fields = ['classes_Int_num', 'classes_Int_cls', 'classes_Int_SubCls', 'classes_MMU_'] for shp, csv in zip(shp_fields, csv_fields): f = layer.fields().indexFromName(csv) f_ = layer.fields().indexFromName(shp) layer.changeAttributeValue(feature.id(), f_, feature[f]) area_km = layer.fields().indexFromName('Area_KM') area_ha = layer.fields().indexFromName('Area_HA') orthoid_field = layer.fields().indexFromName('OrthoID') id_field = layer.fields().indexFromName('Id') layer.changeAttributeValue(feature.id(), area_km, feature.geometry().area() / 10**6) layer.changeAttributeValue(feature.id(), area_ha, feature.geometry().area() / 10**4) ha_areas.append(feature.geometry().area() / 10**4) layer.changeAttributeValue(feature.id(), orthoid_field, feature[0]) layer.changeAttributeValue(feature.id(), id_field, feature.id()) layer.removeJoin(infoLyr.id()) QgsProject.instance().removeMapLayer(infoLyr) fields_to_drop = set(['RuleID', 'Shape_Leng', 'Shape_Area']) field_ids = [] for field in layer.fields(): if field.name() in fields_to_drop: field_ids.append(layer.fields().indexFromName(field.name())) layer.dataProvider().deleteAttributes(field_ids) layer.commitChanges()
def test_JoinUsingExpression2(self): """ test joining a layer using a virtual field (the other way!) """ joinLayer = QgsVectorLayer( "Point?field=x:string&field=y:integer&field=z:integer", "joinlayer", "memory") pr = joinLayer.dataProvider() f1 = QgsFeature() f1.setAttributes(["foo", 246, 321]) f2 = QgsFeature() f2.setAttributes(["bar", 456, 654]) self.assertTrue(pr.addFeatures([f1, f2])) joinLayer.addExpressionField('"y"/2', QgsField('exp1', QVariant.LongLong)) layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory") pr = layer.dataProvider() f = QgsFeature() f.setAttributes(["test", 123]) self.assertTrue(pr.addFeatures([f])) QgsProject.instance().addMapLayers([layer, joinLayer]) join = QgsVectorLayerJoinInfo() join.setTargetFieldName("fldint") join.setJoinLayer(joinLayer) join.setJoinFieldName("exp1") join.setUsingMemoryCache(True) layer.addJoin(join) f = QgsFeature() fi = layer.getFeatures() self.assertTrue(fi.nextFeature(f)) attrs = f.attributes() self.assertEqual(attrs[0], "test") self.assertEqual(attrs[1], 123) self.assertEqual(attrs[2], "foo") self.assertEqual(attrs[3], 246) self.assertEqual(attrs[4], 321) self.assertFalse(fi.nextFeature(f)) QgsProject.instance().removeMapLayers([layer.id(), joinLayer.id()])
def add_joins(self, feedback): """ Add all joins between tables. """ for definition in self.attribute_joins: definition = dict(definition) join_layer = definition['join_layer'] layer_add_join = definition['layer_add_join'] feedback.pushInfo('Ajout de la jointure {} sur {}'.format( join_layer, layer_add_join)) definition['join_layer'] = self.input_layers[join_layer] definition['layer_add_join'] = self.input_layers[layer_add_join] for join in definition['layer_add_join'].vectorJoins(): if definition['join_layer'] == join.joinLayer(): definition['layer_add_join'].removeJoin( join.joinLayer().id()) feedback.pushDebugInfo( 'Removing pre-existing join between {} and {}'.format( definition['layer_add_join'].name(), definition['join_layer'].name())) join_habitat = QgsVectorLayerJoinInfo() join_habitat.setJoinFieldName(definition['join_field_name']) join_habitat.setJoinLayerId(definition['join_layer'].id()) join_habitat.setTargetFieldName(definition['target_field_name']) join_habitat.setPrefix(definition['prefix']) join_habitat.setJoinLayer(definition['join_layer']) if 'block_list' in definition: if Qgis.QGIS_VERSION_INT >= 31400: join_habitat.setJoinFieldNamesBlockList( definition['block_list']) else: join_habitat.setJoinFieldNamesBlackList( definition['block_list']) if not definition['layer_add_join'].addJoin(join_habitat): raise Exception('Join not added {}'.format( definition['join_field_name'])) self.success_join += 1
def test_JoinUsingFeatureRequestExpression(self): """ test requesting features using a filter expression which requires joined columns """ joinLayer = QgsVectorLayer( "Point?field=x:string&field=y:integer&field=z:integer", "joinlayer", "memory") pr = joinLayer.dataProvider() f1 = QgsFeature() f1.setAttributes(["foo", 123, 321]) f2 = QgsFeature() f2.setAttributes(["bar", 124, 654]) self.assertTrue(pr.addFeatures([f1, f2])) layer = QgsVectorLayer( "Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory") pr = layer.dataProvider() f1 = QgsFeature() f1.setAttributes(["test", 123]) f2 = QgsFeature() f2.setAttributes(["test", 124]) self.assertTrue(pr.addFeatures([f1, f2])) QgsProject.instance().addMapLayers([layer, joinLayer]) join = QgsVectorLayerJoinInfo() join.setTargetFieldName("fldint") join.setJoinLayer(joinLayer) join.setJoinFieldName("y") join.setUsingMemoryCache(True) layer.addJoin(join) f = QgsFeature() fi = layer.getFeatures(QgsFeatureRequest().setFlags( QgsFeatureRequest.SubsetOfAttributes).setFilterExpression( 'joinlayer_z=654')) self.assertTrue(fi.nextFeature(f)) self.assertEqual(f['fldint'], 124) self.assertEqual(f['joinlayer_z'], 654) QgsProject.instance().removeMapLayers([layer.id(), joinLayer.id()])
def joinTables(self): d, f = self.lyrPair() for k, v in d.items(): target = QgsProject.instance().mapLayer(k) layerToJoin = QgsProject.instance().mapLayer(v) fieldToJoin = QgsProject.instance() symb = QgsVectorLayerJoinInfo() symb.setJoinFieldName('id_feature') symb.setTargetFieldName('id') symb.setJoinLayerId(layerToJoin.id()) symb.setUsingMemoryCache(True) symb.setEditable(True) symb.setDynamicFormEnabled(True) symb.setUpsertOnEdit(True) symb.setPrefix('') symb.setJoinFieldNamesSubset([ 'ocultar', 'legenda', 'tamanhotxt', 'justtxt', 'orient_txt', 'orient_simb', 'offset_txt', 'offset_simb', 'prioridade', 'offset_txt_x', 'offset_txt_y' ]) symb.setJoinLayer(layerToJoin) target.addJoin(symb)
def configureLayer(self, layer, context, feedback): # rename and style the output layer here layer.setName(self.layerName) layer.loadNamedStyle( os.path.join(os.path.dirname(__file__), 'styles', self.styleName)) layer.triggerRepaint() # set up custom variable identifying the added layers layer.setCustomProperty(NOAA_LAYER_TYPE, self.layerType) # if both layers are available (meaning both post processors have run) then configure joins stationsLayer = currentStationsLayer() predictionsLayer = currentPredictionsLayer() if stationsLayer is not None and predictionsLayer is not None: joinInfo = QgsVectorLayerJoinInfo() joinInfo.setJoinLayer(stationsLayer) joinInfo.setTargetFieldName('station') joinInfo.setJoinFieldName('station') joinInfo.setJoinFieldNamesSubset( ['name', 'timeZoneId', 'timeZoneUTC', 'surface']) joinInfo.setPrefix('station_') predictionsLayer.addJoin(joinInfo) localTimeField = QgsField('local_time', QVariant.DateTime) predictionsLayer.addExpressionField( 'convert_to_time_zone(time, station_timeZoneUTC, station_timeZoneId)', localTimeField) displayDateField = QgsField('display_date', QVariant.String) predictionsLayer.addExpressionField( "format_date(convert_to_time_zone(time, station_timeZoneUTC, station_timeZoneId), 'MM/dd')", displayDateField) displayTimeField = QgsField('display_time', QVariant.String) predictionsLayer.addExpressionField( "format_date(convert_to_time_zone(time, station_timeZoneUTC, station_timeZoneId), 'hh:mm a')", displayTimeField) predictionsLayer.updateFields()
def joinTables(self): d, f = self.lyrPair() for k, v in d.items(): target = QgsProject.instance().mapLayer(k) layerToJoin = QgsProject.instance().mapLayer(v) """ # tests for previous joined layers - under research i = QgsProject.instance().mapLayers().values() for layer in i: fh_lyr = layer joinsInfo = fh_lyr.vectorJoins() if joinsInfo != 0: QMessageBox.critical(iface.mainWindow(), "Error", "Previously Joins already exists! Please remove joins and try again.") break # ask for remove previous joins. use removeJoinTables() else: """ # target.removeJoin(layerToJoin.id()) fieldToJoin = QgsProject.instance() symb = QgsVectorLayerJoinInfo() symb.setJoinFieldName('id_feature') symb.setTargetFieldName('id') symb.setJoinLayerId(layerToJoin.id()) symb.setUsingMemoryCache(True) symb.setEditable(True) symb.setDynamicFormEnabled(True) symb.setUpsertOnEdit(True) symb.setPrefix('') symb.setJoinFieldNamesSubset([ 'ocultar', 'legenda', 'tamanhotxt', 'justtxt', 'orient_txt', 'orient_simb', 'offset_txt', 'offset_simb', 'prioridade', 'offset_txt_x', 'offset_txt_y' ]) symb.setJoinLayer(layerToJoin) target.addJoin(symb) layerToJoin.startEditing() target.triggerRepaint()
def test_JoinUsingFeatureRequestExpression(self): """ test requesting features using a filter expression which requires joined columns """ joinLayer = QgsVectorLayer( "Point?field=x:string&field=y:integer&field=z:integer", "joinlayer", "memory") pr = joinLayer.dataProvider() f1 = QgsFeature() f1.setAttributes(["foo", 123, 321]) f2 = QgsFeature() f2.setAttributes(["bar", 124, 654]) self.assertTrue(pr.addFeatures([f1, f2])) layer = QgsVectorLayer("Point?field=fldtxt:string&field=fldint:integer", "addfeat", "memory") pr = layer.dataProvider() f1 = QgsFeature() f1.setAttributes(["test", 123]) f2 = QgsFeature() f2.setAttributes(["test", 124]) self.assertTrue(pr.addFeatures([f1, f2])) QgsProject.instance().addMapLayers([layer, joinLayer]) join = QgsVectorLayerJoinInfo() join.setTargetFieldName("fldint") join.setJoinLayer(joinLayer) join.setJoinFieldName("y") join.setUsingMemoryCache(True) layer.addJoin(join) f = QgsFeature() fi = layer.getFeatures(QgsFeatureRequest().setFlags(QgsFeatureRequest.SubsetOfAttributes).setFilterExpression('joinlayer_z=654')) self.assertTrue(fi.nextFeature(f)) self.assertEqual(f['fldint'], 124) self.assertEqual(f['joinlayer_z'], 654) QgsProject.instance().removeMapLayers([layer.id(), joinLayer.id()])
def test_value_exists_joins(self): """Test that unique values in fields from joined layers, see GH #36167""" p = QgsProject() main_layer = QgsVectorLayer("Point?field=fid:integer", "main_layer", "memory") self.assertTrue(main_layer.isValid()) # Attr layer is joined with layer on fk -> attr_layer = QgsVectorLayer("Point?field=id:integer&field=fk:integer", "attr_layer", "memory") self.assertTrue(attr_layer.isValid()) p.addMapLayers([main_layer, attr_layer]) join_info = QgsVectorLayerJoinInfo() join_info.setJoinLayer(attr_layer) join_info.setJoinFieldName('fk') join_info.setTargetFieldName('fid') join_info.setUsingMemoryCache(True) main_layer.addJoin(join_info) main_layer.updateFields() join_buffer = main_layer.joinBuffer() self.assertTrue(join_buffer.containsJoins()) self.assertEqual(main_layer.fields().names(), ['fid', 'attr_layer_id']) f = QgsFeature(main_layer.fields()) f.setAttributes([1]) main_layer.dataProvider().addFeatures([f]) f = QgsFeature(attr_layer.fields()) f.setAttributes([1, 1]) attr_layer.dataProvider().addFeatures([f]) self.assertTrue(QgsVectorLayerUtils.valueExists(main_layer, 0, 1)) self.assertTrue(QgsVectorLayerUtils.valueExists(main_layer, 1, 1)) self.assertFalse(QgsVectorLayerUtils.valueExists(main_layer, 0, 2)) self.assertFalse(QgsVectorLayerUtils.valueExists(main_layer, 1, 2))
def processAlgorithm(self, parameters, context, feedback): self.layers = self.parameterAsLayerList(parameters, self.INPUTS, context) self.drop = self.parameterAsBool(parameters, self.DROP_EXISTING_JOINS, context) # return {} # def postProcess(self, context, feedback): # # We try to use postProcess instead of processAlgorithm to propagate joins in the project. # layers = self.layers # drop = self.drop total = len(self.layers) failed = [] feedback.pushDebugInfo('{} layer(s) have been selected.'.format(total)) for i, layer in enumerate(self.layers): # Just trying on more time to get the real layer layer = context.project().mapLayer(layer.id()) if not layer: feedback.reportError( 'Layer {} has not been found in the project. Skipping…'. format(layer.name())) continue feedback.pushInfo('Processing layer \'{}\' with ID {}'.format( layer.name(), layer.id())) joined_fields = [] if self.drop: for vector_join in layer.vectorJoins(): feedback.pushInfo('Removing join \'{}\''.format( vector_join.joinFieldName())) layer.removeJoin(vector_join.joinLayerId()) for field in layer.fields(): widget = field.editorWidgetSetup() if not widget.type() == 'ValueRelation': continue config = widget.config() target_layer = config['Layer'] target_field = config['Key'] source_field = field.name() join_layer = context.project().mapLayer(target_layer) if not join_layer: feedback.reportError( "The layer \"{}\" linked to the field \"{}\" has not been found in the project. " "Skipping this ValueRelation…".format( target_layer, source_field)) continue join = QgsVectorLayerJoinInfo() join.setJoinLayerId(target_layer) join.setJoinFieldName(target_field) join.setTargetFieldName(source_field) join.setUsingMemoryCache(True) feedback.pushInfo( 'Adding join on \'{}\' with prefix \'{}\''.format( field.name(), self.prefix.format(join_layer.name()))) join.setPrefix(self.prefix.format(join_layer.name())) if not layer.addJoin(join): failed.append(layer.name()) feedback.reportError( 'Failed to add the join on {} {}'.format( layer.name(), field.name())) continue for join_field in join_layer.fields(): joined_fields.append( self.prefix.format(join_layer.name()) + join_field.name()) # Uncheck WMS feedback.pushInfo('Unchecking WMS fields') # if Qgis.QGIS_VERSION_INT < 31800: layer.setExcludeAttributesWms(joined_fields) # else: # # Fix for QGIS >= 3.16 # for field in joined_fields: # layer.setFieldConfigurationFlag( # layer.fields().indexFromName(field), QgsField.HideFromWms, True) feedback.pushDebugInfo(', '.join(layer.excludeAttributesWms())) # Uncheck WFS for ids id_fields = [ f for f in joined_fields if f.endswith('_fid') or f.endswith('_id') ] feedback.pushInfo('Unchecking WFS fields') # if Qgis.QGIS_VERSION_INT < 31800: layer.setExcludeAttributesWfs(id_fields) # else: # # Fix for QGIS >= 3.16 # for field in id_fields: # layer.setFieldConfigurationFlag( # layer.fields().indexFromName(field), QgsField.HideFromWfs, True) feedback.pushDebugInfo(', '.join(layer.excludeAttributesWfs())) feedback.setProgress((i + 1) / total * 100) # layer.reload() It does nothing, not enough to propagate the join if failed: msg = 'Some joins failed to be added for : {}'.format( ', '.join(failed)) raise QgsProcessingException(msg) feedback.reportError( 'Everything went fine, BUT you must save your project and reopen it. Joins, WMS and WFS are ' 'not appearing otherwise.') return {}
def test_joined_layers_conversion(self): v1 = QgsVectorLayer( "Point?field=id:integer&field=b_id:integer&field=c_id:integer&field=name:string", "A", "memory") self.assertEqual(v1.isValid(), True) v2 = QgsVectorLayer( "Point?field=id:integer&field=bname:string&field=bfield:integer", "B", "memory") self.assertEqual(v2.isValid(), True) v3 = QgsVectorLayer("Point?field=id:integer&field=cname:string", "C", "memory") self.assertEqual(v3.isValid(), True) QgsProject.instance().addMapLayers([v1, v2, v3]) joinInfo = QgsVectorLayerJoinInfo() joinInfo.setTargetFieldName("b_id") joinInfo.setJoinLayer(v2) joinInfo.setJoinFieldName("id") #joinInfo.setPrefix("B_") v1.addJoin(joinInfo) self.assertEqual(len(v1.fields()), 6) df = QgsVirtualLayerDefinitionUtils.fromJoinedLayer(v1) self.assertEqual( df.query(), 'SELECT t.rowid AS uid, t.id, t.b_id, t.c_id, t.name, j1.bname AS B_bname, j1.bfield AS B_bfield FROM {} AS t LEFT JOIN {} AS j1 ON t."b_id"=j1."id"' .format(v1.id(), v2.id())) # with a field subset v1.removeJoin(v2.id()) joinInfo.setJoinFieldNamesSubset(["bname"]) v1.addJoin(joinInfo) self.assertEqual(len(v1.fields()), 5) df = QgsVirtualLayerDefinitionUtils.fromJoinedLayer(v1) self.assertEqual( df.query(), 'SELECT t.rowid AS uid, t.id, t.b_id, t.c_id, t.name, j1.bname AS B_bname FROM {} AS t LEFT JOIN {} AS j1 ON t."b_id"=j1."id"' .format(v1.id(), v2.id())) joinInfo.setJoinFieldNamesSubset(None) # add a table prefix to the join v1.removeJoin(v2.id()) joinInfo.setPrefix("BB_") v1.addJoin(joinInfo) self.assertEqual(len(v1.fields()), 6) df = QgsVirtualLayerDefinitionUtils.fromJoinedLayer(v1) self.assertEqual( df.query(), 'SELECT t.rowid AS uid, t.id, t.b_id, t.c_id, t.name, j1.bname AS BB_bname, j1.bfield AS BB_bfield FROM {} AS t LEFT JOIN {} AS j1 ON t."b_id"=j1."id"' .format(v1.id(), v2.id())) joinInfo.setPrefix("") v1.removeJoin(v2.id()) v1.addJoin(joinInfo) # add another join joinInfo2 = QgsVectorLayerJoinInfo() joinInfo2.setTargetFieldName("c_id") joinInfo2.setJoinLayer(v3) joinInfo2.setJoinFieldName("id") v1.addJoin(joinInfo2) self.assertEqual(len(v1.fields()), 7) df = QgsVirtualLayerDefinitionUtils.fromJoinedLayer(v1) self.assertEqual(df.query(), ( 'SELECT t.rowid AS uid, t.id, t.b_id, t.c_id, t.name, j1.bname AS B_bname, j1.bfield AS B_bfield, j2.cname AS C_cname FROM {} AS t ' + 'LEFT JOIN {} AS j1 ON t."b_id"=j1."id" ' + 'LEFT JOIN {} AS j2 ON t."c_id"=j2."id"').format( v1.id(), v2.id(), v3.id())) QgsProject.instance().removeMapLayers([v1.id(), v2.id(), v3.id()])
def processAlgorithm(self, parameters, context, feedback): t_file = self.parameterAsVectorLayer( parameters, self.FILE_TABLE, context ) t_troncon = self.parameterAsVectorLayer( parameters, self.SEGMENTS_TABLE, context ) t_obs = self.parameterAsVectorLayer( parameters, self.OBSERVATIONS_TABLE, context ) t_regard = self.parameterAsVectorLayer( parameters, self.MANHOLES_TABLE, context ) g_regard = self.parameterAsVectorLayer( parameters, self.GEOM_MANHOLES, context ) g_troncon = self.parameterAsVectorLayer( parameters, self.GEOM_SEGMENT, context ) g_obs = self.parameterAsVectorLayer( parameters, self.GEOM_OBSERVATION, context ) v_regard = self.parameterAsVectorLayer( parameters, self.VIEW_MANHOLES_GEOLOCALIZED, context ) # define variables variables = context.project().customVariables() variables['itv_rerau_t_file'] = t_file.id() variables['itv_rerau_t_troncon'] = t_troncon.id() variables['itv_rerau_t_obs'] = t_obs.id() variables['itv_rerau_t_regard'] = t_regard.id() variables['itv_rerau_g_regard'] = g_regard.id() variables['itv_rerau_g_troncon'] = g_troncon.id() variables['itv_rerau_g_obs'] = g_obs.id() context.project().setCustomVariables(variables) # define relations relations = [ { 'id': 'fk_obs_id_file', 'name': tr('Link File - Observation'), 'referencingLayer': t_obs.id(), 'referencingField': 'id_file', 'referencedLayer': t_file.id(), 'referencedField': 'id' }, { 'id': 'fk_regard_id_file', 'name': tr('Link File - Manhole'), 'referencingLayer': t_regard.id(), 'referencingField': 'id_file', 'referencedLayer': t_file.id(), 'referencedField': 'id' }, { 'id': 'fk_troncon_id_file', 'name': tr('Link File - Pipe segment'), 'referencingLayer': t_troncon.id(), 'referencingField': 'id_file', 'referencedLayer': t_file.id(), 'referencedField': 'id' }, { 'id': 'fk_obs_id_troncon', 'name': tr('Link Pipe segment - Observation'), 'referencingLayer': t_obs.id(), 'referencingField': 'id_troncon', 'referencedLayer': t_troncon.id(), 'referencedField': 'id' }, { 'id': 'fk_regard_id_geom_regard', 'name': tr('Link Manhole inspection - Reference'), 'referencingLayer': t_regard.id(), 'referencingField': 'id_geom_regard', 'referencedLayer': g_regard.id(), 'referencedField': 'id' }, { 'id': 'fk_troncon_id_geom_trononc', 'name': tr('Link Pipe segment inspection - Reference'), 'referencingLayer': t_troncon.id(), 'referencingField': 'id_geom_troncon', 'referencedLayer': g_troncon.id(), 'referencedField': 'id' } ] relation_manager = context.project().relationManager() for rel_def in relations: feedback.pushInfo( 'Link: {}'.format(rel_def['name']) ) rel = QgsRelation() rel.setId(rel_def['id']) rel.setName(rel_def['name']) rel.setReferencingLayer(rel_def['referencingLayer']) rel.setReferencedLayer(rel_def['referencedLayer']) rel.addFieldPair( rel_def['referencingField'], rel_def['referencedField'] ) rel.setStrength(QgsRelation.Association) relation_manager.addRelation(rel) feedback.pushInfo( 'Count relations {}'.format( len(relation_manager.relations()) ) ) joins = [ { 'layer': t_obs, 'targetField': 'id_troncon', 'joinLayer': t_troncon, 'joinField': 'id', 'fieldNamesSubset': ['ack'] }, { 'layer': g_obs, 'targetField': 'id', 'joinLayer': t_obs, 'joinField': 'id', 'fieldNamesSubset': [] } ] for j_def in joins: layer = j_def['layer'] join = QgsVectorLayerJoinInfo() join.setJoinFieldName(j_def['joinField']) join.setJoinLayerId(j_def['joinLayer'].id()) join.setTargetFieldName(j_def['targetField']) if j_def['fieldNamesSubset']: join.setJoinFieldNamesSubset(j_def['fieldNamesSubset']) join.setUsingMemoryCache(False) join.setPrefix('') join.setEditable(False) join.setCascadedDelete(False) join.setJoinLayer(j_def['joinLayer']) layer.addJoin(join) layer.updateFields() # load styles styles = [ { 'layer': t_file, 'namedStyles': [ { 'file': 'itv_file_fields.qml', 'type': QgsMapLayer.Fields }, { 'file': 'itv_file_actions.qml', 'type': QgsMapLayer.Actions } ] }, { 'layer': t_troncon, 'namedStyles': [ { 'file': 'itv_troncon_fields.qml', 'type': QgsMapLayer.Fields }, { 'file': 'itv_troncon_table.qml', 'type': QgsMapLayer.AttributeTable } ] }, { 'layer': t_obs, 'namedStyles': [ { 'file': 'itv_obs_fields.qml', 'type': QgsMapLayer.Fields }, { 'file': 'itv_obs_table.qml', 'type': QgsMapLayer.AttributeTable } ] }, { 'layer': t_regard, 'namedStyles': [ { 'file': 'itv_regard_fields.qml', 'type': QgsMapLayer.Fields }, { 'file': 'itv_regard_forms.qml', 'type': QgsMapLayer.Forms }, { 'file': 'itv_regard_table.qml', 'type': QgsMapLayer.AttributeTable } ] }, { 'layer': g_regard, 'namedStyles': [ { 'file': 'itv_geom_regard_fields.qml', 'type': QgsMapLayer.Fields }, { 'file': 'itv_geom_regard_symbology.qml', 'type': QgsMapLayer.Symbology } ] }, { 'layer': g_troncon, 'namedStyles': [ { 'file': 'itv_geom_troncon_fields.qml', 'type': QgsMapLayer.Fields }, { 'file': 'itv_geom_troncon_symbology.qml', 'type': QgsMapLayer.Symbology }, { 'file': 'itv_geom_troncon_actions.qml', 'type': QgsMapLayer.Actions } ] }, { 'layer': g_obs, 'namedStyles': [ { 'file': 'itv_geom_obs_fields.qml', 'type': QgsMapLayer.Fields }, { 'file': 'itv_geom_obs_symbology.qml', 'type': QgsMapLayer.Symbology } ] }, { 'layer': v_regard, 'namedStyles': [ { 'file': 'itv_view_regard_fields.qml', 'type': QgsMapLayer.Fields }, { 'file': 'itv_view_regard_symbology.qml', 'type': QgsMapLayer.Symbology }, { 'file': 'itv_view_regard_labeling.qml', 'type': QgsMapLayer.Labeling } ] } ] for style in styles: layer = style['layer'] for n_style in style['namedStyles']: layer.loadNamedStyle( resources_path('styles', n_style['file']), categories=n_style['type'] ) # layer.saveStyleToDatabase('style', 'default style', True, '') layer.triggerRepaint() # Creation de la symbologie g_obs g_obs_rules = ( 'BAA', 'BAB', 'BAC', 'BAD', 'BAE', 'BAF', 'BAG', 'BAH', 'BAI', 'BAJ', 'BAK', 'BAL', 'BAM', 'BAN', 'BAO', 'BAP', 'BBA', 'BBB', 'BBC', 'BBD', 'BBE', 'BBF', 'BBG', 'BBH', 'BCA', 'BCB', 'BCC', 'BDA', 'BDB', 'BDC', 'BDD', 'BDE', 'BDF', 'BDG' ) g_obs_rule_descs = { 'BAA': 'Déformation', 'BAB': 'Fissure', 'BAC': 'Rupture/Effondrement', 'BAD': 'Elt maçonnerie', 'BAE': 'Mortier manquant', 'BAF': 'Dégradation de surface', 'BAG': 'Branchement pénétrant', 'BAH': 'Raccordement défectueux', 'BAI': 'Joint étanchéité apparent', 'BAJ': 'Déplacement d\'assemblage', 'BAK': 'Défaut de révêtement', 'BAL': 'Réparation défectueuse', 'BAM': 'Défaut soudure', 'BAN': 'Conduite poreuse', 'BAO': 'Sol visible', 'BAP': 'Trou visible', 'BBA': 'Racines', 'BBB': 'Dépots Adhérents', 'BBC': 'Dépôts', 'BBD': 'Entrée de terre', 'BBE': 'Autres obstacles', 'BBF': 'Infiltration', 'BBG': 'Exfiltration', 'BBH': 'Vermine', 'BCA': 'Raccordement', 'BCB': 'Réparation', 'BCC': 'Courbure de collecteur', 'BDA': 'Photographie générale', 'BDB': 'Remarque générale', 'BDC': 'Inspection abandonnée', 'BDD': 'Niveau d\'eau', 'BDE': 'Ecoulement dans une canlisation entrante', 'BDF': 'Atmosphère canalisation', 'BDG': 'Perte de visibilité' } g_obs_rootrule = QgsRuleBasedRenderer.Rule(None) rendering_pass_idx = len(g_obs_rules) for rule in g_obs_rules: # get svg path svg_path = resources_path('styles', 'img_obs', rule + '.svg') # create svg symbol layer svg_symbol_layer = QgsSvgMarkerSymbolLayer(svg_path) svg_symbol_layer.setRenderingPass(rendering_pass_idx) # create white square symbol layer for the backend simple_symbol_layer = QgsSimpleMarkerSymbolLayer( shape=QgsSimpleMarkerSymbolLayerBase.Circle, size=svg_symbol_layer.size(), color=QColor('white'), strokeColor=QColor('white') ) simple_symbol_layer.setRenderingPass(rendering_pass_idx) # create marker svg_marker = QgsMarkerSymbol() # set the backend symbol layer svg_marker.changeSymbolLayer(0, simple_symbol_layer) # add svg symbol layer svg_marker.appendSymbolLayer(svg_symbol_layer) # create rule svg_rule = QgsRuleBasedRenderer.Rule( svg_marker, 0, 10000, QgsExpression.createFieldEqualityExpression('a', rule), rule ) if rule in g_obs_rule_descs: svg_rule.setLabel(g_obs_rule_descs[rule]) svg_rule.setDescription('{}: {}'.format( rule, g_obs_rule_descs[rule] )) # add rule g_obs_rootrule.appendChild(svg_rule) rendering_pass_idx -= 1 g_obs_rootrule.appendChild( QgsRuleBasedRenderer.Rule( QgsMarkerSymbol.createSimple( { 'name': 'circle', 'color': '#0000b2', 'outline_color': '#0000b2', 'size': '1' } ), 0, 10000, 'ELSE', 'Autres' ) ) g_obs.setRenderer(QgsRuleBasedRenderer(g_obs_rootrule)) feedback.pushInfo('Project has been setup') return {}
def test_joined_layers_conversion(self): v1 = QgsVectorLayer( "Point?field=id:integer&field=b_id:integer&field=c_id:integer&field=name:string", "A", "memory") self.assertEqual(v1.isValid(), True) v2 = QgsVectorLayer( "Point?field=id:integer&field=bname:string&field=bfield:integer", "B", "memory") self.assertEqual(v2.isValid(), True) v3 = QgsVectorLayer("Point?field=id:integer&field=cname:string", "C", "memory") self.assertEqual(v3.isValid(), True) tl1 = QgsVectorLayer( "NoGeometry?field=id:integer&field=e_id:integer&field=0name:string", "D", "memory") self.assertEqual(tl1.isValid(), True) tl2 = QgsVectorLayer("NoGeometry?field=id:integer&field=ena me:string", "E", "memory") self.assertEqual(tl2.isValid(), True) QgsProject.instance().addMapLayers([v1, v2, v3, tl1, tl2]) joinInfo = QgsVectorLayerJoinInfo() joinInfo.setTargetFieldName("b_id") joinInfo.setJoinLayer(v2) joinInfo.setJoinFieldName("id") #joinInfo.setPrefix("B_") v1.addJoin(joinInfo) self.assertEqual(len(v1.fields()), 6) df = QgsVirtualLayerDefinitionUtils.fromJoinedLayer(v1) self.assertEqual( df.query(), 'SELECT t.geometry, t.rowid AS uid, t."id", t."b_id", t."c_id", t."name", j1."bname" AS "B_bname", j1."bfield" AS "B_bfield" FROM "{}" AS t LEFT JOIN "{}" AS j1 ON t."b_id"=j1."id"' .format(v1.id(), v2.id())) # with a field subset v1.removeJoin(v2.id()) joinInfo.setJoinFieldNamesSubset(["bname"]) v1.addJoin(joinInfo) self.assertEqual(len(v1.fields()), 5) df = QgsVirtualLayerDefinitionUtils.fromJoinedLayer(v1) self.assertEqual( df.query(), 'SELECT t.geometry, t.rowid AS uid, t."id", t."b_id", t."c_id", t."name", j1."bname" AS "B_bname" FROM "{}" AS t LEFT JOIN "{}" AS j1 ON t."b_id"=j1."id"' .format(v1.id(), v2.id())) joinInfo.setJoinFieldNamesSubset(None) # add a table prefix to the join v1.removeJoin(v2.id()) joinInfo.setPrefix("BB_") v1.addJoin(joinInfo) self.assertEqual(len(v1.fields()), 6) df = QgsVirtualLayerDefinitionUtils.fromJoinedLayer(v1) self.assertEqual( df.query(), 'SELECT t.geometry, t.rowid AS uid, t."id", t."b_id", t."c_id", t."name", j1."bname" AS "BB_bname", j1."bfield" AS "BB_bfield" FROM "{}" AS t LEFT JOIN "{}" AS j1 ON t."b_id"=j1."id"' .format(v1.id(), v2.id())) joinInfo.setPrefix("") v1.removeJoin(v2.id()) v1.addJoin(joinInfo) # add another join joinInfo2 = QgsVectorLayerJoinInfo() joinInfo2.setTargetFieldName("c_id") joinInfo2.setJoinLayer(v3) joinInfo2.setJoinFieldName("id") v1.addJoin(joinInfo2) self.assertEqual(len(v1.fields()), 7) df = QgsVirtualLayerDefinitionUtils.fromJoinedLayer(v1) self.assertEqual(df.query(), ( 'SELECT t.geometry, t.rowid AS uid, t."id", t."b_id", t."c_id", t."name", j1."bname" AS "B_bname", j1."bfield" AS "B_bfield", j2."cname" AS "C_cname" FROM "{}" AS t ' + 'LEFT JOIN "{}" AS j1 ON t."b_id"=j1."id" ' + 'LEFT JOIN "{}" AS j2 ON t."c_id"=j2."id"').format( v1.id(), v2.id(), v3.id())) # test NoGeometry joined layers with field names starting with a digit or containing white spaces joinInfo3 = QgsVectorLayerJoinInfo() joinInfo3.setTargetFieldName("e_id") joinInfo3.setJoinLayer(tl2) joinInfo3.setJoinFieldName("id") tl1.addJoin(joinInfo3) self.assertEqual(len(tl1.fields()), 4) df = QgsVirtualLayerDefinitionUtils.fromJoinedLayer(tl1) self.assertEqual( df.query(), 'SELECT t.rowid AS uid, t."id", t."e_id", t."0name", j1."ena me" AS "E_ena me" FROM "{}" AS t LEFT JOIN "{}" AS j1 ON t."e_id"=j1."id"' .format(tl1.id(), tl2.id())) QgsProject.instance().removeMapLayers( [v1.id(), v2.id(), v3.id(), tl1.id(), tl2.id()])
def add_joined_layer( source_layer: Union[FeatureLayer, StandaloneTable], # pylint: disable=too-many-branches input_file, base_layer: QgsVectorLayer, context: Context): """ Adds joined layers """ if not source_layer.join: return None if isinstance(source_layer.join, MemoryRelationshipClassName): if isinstance(source_layer.join.origin_name, RelQueryTableName): if context.unsupported_object_callback: context.unsupported_object_callback( '{}: Nested joins are not supported in QGIS'.format( context.layer_name), level=Context.CRITICAL) return None join_info = QgsVectorLayerJoinInfo() join_info.setJoinFieldName(source_layer.join.origin_primary_key) join_info.setTargetFieldName(source_layer.join.origin_foreign_key) base, _ = os.path.split(input_file) source_layer_props = DatasetNameConverter.convert( name=source_layer.join.destination_name, base=base, crs=QgsCoordinateReferenceSystem(), context=context) context.layer_type_hint = source_layer_props.wkb_type name = 'join' if hasattr(source_layer.join.destination_name, 'name'): name = source_layer.join.destination_name.name join_info.setPrefix(name + '.') if Qgis.QGIS_VERSION_INT >= 30800: opts = QgsVectorLayer.LayerOptions() if source_layer_props.wkb_type is not None: opts.fallbackWkbType = source_layer_props.wkb_type vl = QgsVectorLayer(source_layer_props.uri, name, source_layer_props.provider, opts) else: vl = QgsVectorLayer(source_layer_props.uri, name, source_layer_props.provider) if not vl.isValid() and Qgis.QGIS_VERSION_INT < 30600: if source_layer_props.provider == 'ogr' and not os.path.exists( source_layer_props.file_name ) and context.invalid_layer_resolver: res = context.invalid_layer_resolver( source_layer.join.name, source_layer_props.uri, source_layer_props.wkb_type) source_layer_props.uri = res.uri source_layer_props.provider = res.providerKey vl = QgsVectorLayer(source_layer_props.uri, 'join', source_layer_props.provider) # todo layer name vl.setRenderer(QgsNullSymbolRenderer()) try: vl.setFlags(vl.flags() | QgsMapLayer.Private) except AttributeError: pass join_info.setJoinLayer(vl) base_layer.addJoin(join_info) return vl else: if context.unsupported_object_callback: context.unsupported_object_callback( '{}: Join layers of type {} are not yet supported'.format( context.layer_name, source_layer.join.__class__.__name__), level=Context.CRITICAL) return None
def run(self): project_id = self.settings.value("project/id") epsg = self.settings.value("project/epsg") locale = QSettings().value('locale/userLocale')[ 0:2] # this is for multilingual legends # If locale is different to frence or italian, german will be used. # Otherwise we get into troubles with the legends, e.g. locale = "en" # but # there is no english legend (qml file). if locale == "fr": pass elif locale == "it": pass else: locale = "de" if not project_id: self.message_bar.pushCritical( "Error", _translate("VeriSO_V+D_FP2", "project_id not set", None)) return QApplication.setOverrideCursor(Qt.WaitCursor) try: group = _translate("VeriSO_V+D_FP2", "FixpunkteKategorie2", None) group += " (" + str(project_id) + ")" # Lagefixpunkte 2 layer = { "type": "postgres", "title": _translate("VeriSO_V+D_FP2", "LFP2 Nachführung", None), "featuretype": "fixpunktekategorie2_lfp2nachfuehrung", "geom": "perimeter", "key": "ogc_fid", "sql": "", "readonly": True, "group": group } # Visibility and if legend and/or groupd should be collapsed can # be set with parameters in the self.layer_loader.load() # method: # load(layer, visibility=True, collapsed_legend=False, # collapsed_group=False) vlayer_lfp2_nf = self.layer_loader.load(layer, False, True) layer = { "type": "postgres", "title": _translate("VeriSO_V+D_FP2", "LFP2", None), "featuretype": "fixpunktekategorie2_lfp2", "geom": "geometrie", "key": "ogc_fid", "sql": "", "readonly": True, "group": group, "style": "fixpunkte/lfp2.qml" } vlayer_lfp2 = self.layer_loader.load(layer) # Join two layers (lfp2 and lfp2nachfuehrung) lfp2_field = "entstehung" lfp2_nf_field = "ogc_fid" join_obj = QgsVectorLayerJoinInfo() join_obj.setJoinLayerId(vlayer_lfp2_nf.id()) join_obj.setJoinFieldName(lfp2_nf_field) join_obj.setTargetFieldName(lfp2_field) join_obj.setUsingMemoryCache(True) join_obj.setPrefix("lfp2_nf_") vlayer_lfp2.addJoin(join_obj) # This is how WMS layer work. layer = { "type": "wms", "title": _translate("VeriSO_V+D_FP2", "LFP2 Schweiz (WMS)", None), "url": "http://wms.geo.admin.ch/", "layers": "ch.swisstopo.fixpunkte-lfp2", "format": "image/png", "crs": "EPSG:" + str(epsg), "group": group } vlayer = self.layer_loader.load(layer, False, True) # Höhenfixpunkte 2 layer = { "type": "postgres", "title": _translate("VeriSO_V+D_FP2", "HFP2 Nachführung", None), "featuretype": "fixpunktekategorie2_hfp2nachfuehrung", "geom": "perimeter", "key": "ogc_fid", "sql": "", "readonly": True, "group": group } vlayer_hfp2_nf = self.layer_loader.load(layer, False, True) layer = { "type": "postgres", "title": _translate("VeriSO_V+D_FP2", "HFP2", None), "featuretype": "fixpunktekategorie2_hfp2", "geom": "geometrie", "key": "ogc_fid", "sql": "", "readonly": True, "group": group, "style": "fixpunkte/hfp2.qml" } vlayer_hfp2 = self.layer_loader.load(layer) # Join two layers (hfp2 and hfp2nachfuehrung) hfp2_field = "entstehung" hfp2_nf_field = "ogc_fid" join_obj = QgsVectorLayerJoinInfo() join_obj.setJoinLayerId(vlayer_hfp2_nf.id()) join_obj.setJoinFieldName(hfp2_nf_field) join_obj.setTargetFieldName(hfp2_field) join_obj.setUsingMemoryCache(True) join_obj.setPrefix("hfp2_nf_") vlayer_hfp2.addJoin(join_obj) layer = { "type": "wms", "title": _translate("VeriSO_V+D_FP2", "HFP2 Schweiz (WMS)", None), "url": "http://wms.geo.admin.ch/", "layers": "ch.swisstopo.fixpunkte-hfp2", "format": "image/png", "crs": "EPSG:" + str(epsg), "group": group } vlayer = self.layer_loader.load(layer, False, True) # Business as usual: Gemeindegrenzen layer = { "type": "postgres", "title": _translate("VeriSO_V+D_FP2", "Gemeindegrenze", None), "featuretype": "gemeindegrenzen_gemeindegrenze", "geom": "geometrie", "key": "ogc_fid", "sql": "", "readonly": True, "group": group, "style": "global_qml/gemeindegrenze/gemgre_strichliert.qml" } gemgrelayer = self.layer_loader.load(layer) # Change map extent. # Bug (?) in QGIS: http://hub.qgis.org/issues/10980 # Closed for the lack of feedback. Upsi... # Still a problem? (sz / 2015-04-12) if gemgrelayer: rect = gemgrelayer.extent() rect.scale(5) self.iface.mapCanvas().setExtent(rect) self.iface.mapCanvas().refresh() # Sometimes it does make much more sense # to zoom to maximal extent: # self.iface.mapCanvas().zoomToFullExtent() except Exception: QApplication.restoreOverrideCursor() exc_type, exc_value, exc_traceback = sys.exc_info() self.message_bar.pushMessage( "Error", str(traceback.format_exc(exc_traceback)), level=Qgis.Critical, duration=0) QApplication.restoreOverrideCursor()
def testJoinedFieldIsEditableRole(self): layer = QgsVectorLayer("Point?field=id_a:integer", "addfeat", "memory") layer2 = QgsVectorLayer("Point?field=id_b:integer&field=value_b", "addfeat", "memory") QgsProject.instance().addMapLayers([layer, layer2]) # editable join join_info = QgsVectorLayerJoinInfo() join_info.setTargetFieldName("id_a") join_info.setJoinLayer(layer2) join_info.setJoinFieldName("id_b") join_info.setPrefix("B_") join_info.setEditable(True) join_info.setUpsertOnEdit(True) layer.addJoin(join_info) m = QgsFieldModel() m.setLayer(layer) self.assertIsNone( m.data(m.indexFromName('id_a'), QgsFieldModel.JoinedFieldIsEditable)) self.assertTrue( m.data(m.indexFromName('B_value_b'), QgsFieldModel.JoinedFieldIsEditable)) self.assertIsNone( m.data(m.indexFromName('an expression'), QgsFieldModel.JoinedFieldIsEditable)) self.assertIsNone( m.data(m.indexFromName(None), QgsFieldModel.JoinedFieldIsEditable)) m.setAllowExpression(True) m.setExpression('an expression') self.assertIsNone( m.data(m.indexFromName('an expression'), QgsFieldModel.JoinedFieldIsEditable)) m.setAllowEmptyFieldName(True) self.assertIsNone( m.data(m.indexFromName(None), QgsFieldModel.JoinedFieldIsEditable)) proxy_m = QgsFieldProxyModel() proxy_m.setFilters(QgsFieldProxyModel.AllTypes | QgsFieldProxyModel.HideReadOnly) proxy_m.sourceFieldModel().setLayer(layer) self.assertEqual(proxy_m.rowCount(), 2) self.assertEqual(proxy_m.data(proxy_m.index(0, 0)), 'id_a') self.assertEqual(proxy_m.data(proxy_m.index(1, 0)), 'B_value_b') # not editable join layer3 = QgsVectorLayer("Point?field=id_a:integer", "addfeat", "memory") QgsProject.instance().addMapLayers([layer3]) join_info = QgsVectorLayerJoinInfo() join_info.setTargetFieldName("id_a") join_info.setJoinLayer(layer2) join_info.setJoinFieldName("id_b") join_info.setPrefix("B_") join_info.setEditable(False) layer3.addJoin(join_info) m = QgsFieldModel() m.setLayer(layer3) self.assertIsNone( m.data(m.indexFromName('id_a'), QgsFieldModel.JoinedFieldIsEditable)) self.assertFalse( m.data(m.indexFromName('B_value_b'), QgsFieldModel.JoinedFieldIsEditable)) self.assertIsNone( m.data(m.indexFromName('an expression'), QgsFieldModel.JoinedFieldIsEditable)) self.assertIsNone( m.data(m.indexFromName(None), QgsFieldModel.JoinedFieldIsEditable)) m.setAllowExpression(True) m.setExpression('an expression') self.assertIsNone( m.data(m.indexFromName('an expression'), QgsFieldModel.JoinedFieldIsEditable)) m.setAllowEmptyFieldName(True) self.assertIsNone( m.data(m.indexFromName(None), QgsFieldModel.JoinedFieldIsEditable)) proxy_m = QgsFieldProxyModel() proxy_m.sourceFieldModel().setLayer(layer3) proxy_m.setFilters(QgsFieldProxyModel.AllTypes | QgsFieldProxyModel.HideReadOnly) self.assertEqual(proxy_m.rowCount(), 1) self.assertEqual(proxy_m.data(proxy_m.index(0, 0)), 'id_a')
def test_joined_layers_conversion(self): v1 = QgsVectorLayer("Point?field=id:integer&field=b_id:integer&field=c_id:integer&field=name:string", "A", "memory") self.assertEqual(v1.isValid(), True) v2 = QgsVectorLayer("Point?field=id:integer&field=bname:string&field=bfield:integer", "B", "memory") self.assertEqual(v2.isValid(), True) v3 = QgsVectorLayer("Point?field=id:integer&field=cname:string", "C", "memory") self.assertEqual(v3.isValid(), True) tl1 = QgsVectorLayer("NoGeometry?field=id:integer&field=e_id:integer&field=0name:string", "D", "memory") self.assertEqual(tl1.isValid(), True) tl2 = QgsVectorLayer("NoGeometry?field=id:integer&field=ena me:string", "E", "memory") self.assertEqual(tl2.isValid(), True) QgsProject.instance().addMapLayers([v1, v2, v3, tl1, tl2]) joinInfo = QgsVectorLayerJoinInfo() joinInfo.setTargetFieldName("b_id") joinInfo.setJoinLayer(v2) joinInfo.setJoinFieldName("id") #joinInfo.setPrefix("B_") v1.addJoin(joinInfo) self.assertEqual(len(v1.fields()), 6) df = QgsVirtualLayerDefinitionUtils.fromJoinedLayer(v1) self.assertEqual(df.query(), 'SELECT t.geometry, t.rowid AS uid, t."id", t."b_id", t."c_id", t."name", j1."bname" AS "B_bname", j1."bfield" AS "B_bfield" FROM "{}" AS t LEFT JOIN "{}" AS j1 ON t."b_id"=j1."id"'.format(v1.id(), v2.id())) # with a field subset v1.removeJoin(v2.id()) joinInfo.setJoinFieldNamesSubset(["bname"]) v1.addJoin(joinInfo) self.assertEqual(len(v1.fields()), 5) df = QgsVirtualLayerDefinitionUtils.fromJoinedLayer(v1) self.assertEqual(df.query(), 'SELECT t.geometry, t.rowid AS uid, t."id", t."b_id", t."c_id", t."name", j1."bname" AS "B_bname" FROM "{}" AS t LEFT JOIN "{}" AS j1 ON t."b_id"=j1."id"'.format(v1.id(), v2.id())) joinInfo.setJoinFieldNamesSubset(None) # add a table prefix to the join v1.removeJoin(v2.id()) joinInfo.setPrefix("BB_") v1.addJoin(joinInfo) self.assertEqual(len(v1.fields()), 6) df = QgsVirtualLayerDefinitionUtils.fromJoinedLayer(v1) self.assertEqual(df.query(), 'SELECT t.geometry, t.rowid AS uid, t."id", t."b_id", t."c_id", t."name", j1."bname" AS "BB_bname", j1."bfield" AS "BB_bfield" FROM "{}" AS t LEFT JOIN "{}" AS j1 ON t."b_id"=j1."id"'.format(v1.id(), v2.id())) joinInfo.setPrefix("") v1.removeJoin(v2.id()) v1.addJoin(joinInfo) # add another join joinInfo2 = QgsVectorLayerJoinInfo() joinInfo2.setTargetFieldName("c_id") joinInfo2.setJoinLayer(v3) joinInfo2.setJoinFieldName("id") v1.addJoin(joinInfo2) self.assertEqual(len(v1.fields()), 7) df = QgsVirtualLayerDefinitionUtils.fromJoinedLayer(v1) self.assertEqual(df.query(), ('SELECT t.geometry, t.rowid AS uid, t."id", t."b_id", t."c_id", t."name", j1."bname" AS "B_bname", j1."bfield" AS "B_bfield", j2."cname" AS "C_cname" FROM "{}" AS t ' + 'LEFT JOIN "{}" AS j1 ON t."b_id"=j1."id" ' + 'LEFT JOIN "{}" AS j2 ON t."c_id"=j2."id"').format(v1.id(), v2.id(), v3.id())) # test NoGeometry joined layers with field names starting with a digit or containing white spaces joinInfo3 = QgsVectorLayerJoinInfo() joinInfo3.setTargetFieldName("e_id") joinInfo3.setJoinLayer(tl2) joinInfo3.setJoinFieldName("id") tl1.addJoin(joinInfo3) self.assertEqual(len(tl1.fields()), 4) df = QgsVirtualLayerDefinitionUtils.fromJoinedLayer(tl1) self.assertEqual(df.query(), 'SELECT t.rowid AS uid, t."id", t."e_id", t."0name", j1."ena me" AS "E_ena me" FROM "{}" AS t LEFT JOIN "{}" AS j1 ON t."e_id"=j1."id"'.format(tl1.id(), tl2.id())) QgsProject.instance().removeMapLayers([v1.id(), v2.id(), v3.id(), tl1.id(), tl2.id()])
def fusionnerJointure(self, cheminCompletParcelle, jointureChoisie): """ Selon les tables déja ouverte dans le projet : ouverture si necessaire des différents cas de délimiteurs Jointure par QGIS """ # Vérification du projet ouverte monProjet = QgsProject.instance() if monProjet.fileName() == None or monProjet.fileName() == "": monPrint("Projet en cours de création", T_WAR) else: monPrint("Projet ouvert {}".format(monProjet.fileName())) root = monProjet.layerTreeRoot() # Création du groupe jointure_date dateMaintenant = datetime.now() nomGroupe = MonParcellaire_JOI + " du " + dateMaintenant.strftime( "%d %b à %Hh%M:%S") temporaireGroupe = QgsLayerTreeGroup(nomGroupe) # Positionner en haut de root root.addChildNode(temporaireGroupe) nouveauGroupe = temporaireGroupe.clone() root.insertChildNode(0, nouveauGroupe) root.removeChildNode(temporaireGroupe) # Ouverture du vecteur parcelle parcelle = QgsVectorLayer( cheminCompletParcelle, MonParcellaire_PAR + SEP_U + MonParcellaire_JOI, 'ogr') monProjet.addMapLayer(parcelle, False) nouveauGroupe.addLayer(parcelle) # Recherche delimiteur delimiteur, csv, nomCsv = self.rechercherDelimiteurJointure( jointureChoisie, "No Pandas") nomCourtJointure = os.path.basename(jointureChoisie) monPrint( "Délimiteur identifié {0} pour {1}".format(delimiteur, nomCourtJointure), T_OK) monProjet.addMapLayer(csv, False) nouveauGroupe.addLayer(csv) # Jointure attributsSelectionnes = self.AttributsAJoindre_listWidget.selectedItems( ) attributsAJoindre = [] for positionAttribut in range(len(attributsSelectionnes)): attributsAJoindre.append( str(self.AttributsAJoindre_listWidget.selectedItems() [positionAttribut].text())) #monPrint( "Attributs à joindre {}".format( attributsAJoindre)) # Liste des champs dans csv nomColonnes, _ = self.lireAttributsJointure(jointureChoisie) attributsAJoindreOrdonne = [] for col in nomColonnes: if col in attributsAJoindre: if col != MonParcellaireNomAttribut: attributsAJoindreOrdonne.append(col) #monPrint( "Attributs à joindre ordonné {}".format( attributsAJoindreOrdonne)) champVecteur = MonParcellaireNomAttribut maJointure = QgsVectorLayerJoinInfo() champCsv = self.AttributJointure_comboBox.currentText() maJointure.setJoinFieldName(champCsv) maJointure.setTargetFieldName(champVecteur) maJointure.setUsingMemoryCache(True) maJointure.setPrefix("") maJointure.setJoinLayer(csv) # Récupérer les champs de jointure maJointure.setJoinFieldNamesSubset(attributsAJoindreOrdonne) parcelle.addJoin(maJointure) return jointureChoisie, attributsAJoindreOrdonne
def join_field(input_table, join_table, field_to_calc, field_to_copy, joinfield_input_table, joinfield_join_table, inner_join=False): """Veld overnemen uit andere tabel o.b.v. tablejoin. Het veld wat gevuld moet worden (field_to_calc) moet al wel bestaan en wordt in deze functie alleen gevuld. Vul "pk" in bij joinfield_join_table om de primary key te laten bepalen of kies een ander veld""" # voorbeeld: join_field(input_table="", join_table="", field_to_calc="", field_to_copy="", joinfield_input_table="", joinfield_join_table="") if 1 == 1: print_log( "joining field {} from {}...".format( field_to_calc, os.path.basename(join_table.name())), "d") input_table.selectByIds([]) # add join old way qgis 2 ## joinObject = QgsVectorJoinInfo() ## joinObject.joinLayerId = join_table.id() ## joinObject.joinFieldName = joinfield_join_table ## joinObject.joinFieldName = joinfield_join_table ## joinObject.targetFieldName = joinfield_input_table # add join qgis 3 joinObject = QgsVectorLayerJoinInfo() # old: QgsVectorJoinInfo() joinObject.setJoinLayer(join_table) joinObject.setJoinFieldName(joinfield_join_table) joinObject.setTargetFieldName(joinfield_input_table) if not input_table.addJoin(joinObject): print_log("join failed!", "w") # calculate field context = QgsExpressionContext() scope = QgsExpressionContextScope() context.appendScope(scope) e = QgsExpression('"{}_{}"'.format(join_table.name(), field_to_copy)) ##e.prepare(input_table.fields()) # qgis 2 print_log( "expression = {}".format('"{}_{}"'.format(join_table.name(), field_to_copy)), "d") idx_field_to_copy = input_table.fields().indexFromName('{}_{}'.format( join_table.name(), field_to_copy)) if idx_field_to_copy == -1: print_log( "[{}] is leeg omdat [{}] ontbreekt in kaartlaag '{}'.".format( field_to_calc, field_to_copy, join_table.name()), "w") idx_joinfield_join_table = join_table.fields().indexFromName( joinfield_join_table) if idx_joinfield_join_table == -1: print_log( "join_field [{}] ontbreekt in {}. table join mislukt.".format( joinfield_join_table, join_table.name()), "w") input_table.startEditing() idx = input_table.fields().indexFromName(field_to_calc) if idx == -1: print_log( "field_to_calculate [{}] niet gevonden in kaartlaag '{}'.". format(field_to_calc, input_table.name()), "w") if inner_join: print_log("inner_join = True", 'd') s_expr = '"{}_{}" IS NOT NULL'.format(join_table.name(), field_to_copy) print_log(s_expr, 'd') expr = QgsExpression(s_expr) it = input_table.getFeatures( QgsFeatureRequest(expr)) # iterator object input_table.selectByIds([i.id() for i in it]) features = input_table.selectedFeatures() else: features = input_table.getFeatures() for f in features: scope.setFeature(f) f[idx] = e.evaluate(context) # qgis 2: e.evaluate(f) input_table.updateFeature(f) input_table.commitChanges() input_table.removeJoin(joinObject.joinLayerId())
def run(self): project_id = self.settings.value("project/id") epsg = self.settings.value("project/epsg") self.project_dir = self.settings.value("project/projectdir") self.project_id = self.settings.value("project/id") locale = QSettings().value('locale/userLocale')[ 0:2] # this is for multilingual legends # If locale is different to frence or italian, german will be used. # Otherwise we get into troubles with the legends, e.g. locale = "en" # but # there is no english legend (qml file). if locale == "fr": pass elif locale == "it": pass else: locale = "de" if not project_id: self.message_bar.pushCritical("Error", _translate("VeriSO_V+D_FP3", "project_id not set", None)) return QApplication.setOverrideCursor(Qt.WaitCursor) try: group = _translate("VeriSO_V+D_FP3", "FixpunkteKategorie3", None) group += " (" + str(project_id) + ")" layer = { "type": "postgres", "title": _translate("VeriSO_V+D_FP3", "Toleranzstufen", None), "featuretype": "tseinteilung_toleranzstufe", "geom": "geometrie", "key": "ogc_fid", "sql": "", "readonly": True, "group": group, "style": "tseinteilung/toleranzstufe_" + locale + ".qml" } # Visibility and if legend and/or groupd should be collapsed can # be set with parameters in the self.layer_loader.load() # method: # load(layer, visibility=True, collapsed_legend=False, # collapsed_group=False) vlayer = self.layer_loader.load(layer) layer = { "type": "postgres", "title": _translate("VeriSO_V+D_FP3", "LFP3 Nachführung", None), "featuretype": "fixpunktekategorie3_lfp3nachfuehrung", "geom": "perimeter", "key": "ogc_fid", "sql": "", "readonly": True, "group": group } vlayer_lfp3_nf = self.layer_loader.load(layer, False, True) layer = { "type": "postgres", "title": _translate("VeriSO_V+D_FP3", "LFP3", None), "featuretype": "fixpunktekategorie3_lfp3", "geom": "geometrie", "key": "ogc_fid", "sql": "", "readonly": True, "group": group, "style": "fixpunkte/lfp3_" + locale + ".qml" } vlayer_lfp3 = self.layer_loader.load(layer) # Join two layers (lfp3 and lfp3nachfuehrung) lfp3_field = "entstehung" lfp3_nf_field = "ogc_fid" join_obj = QgsVectorLayerJoinInfo() join_obj.setJoinLayerId(vlayer_lfp3_nf.id()) join_obj.setJoinFieldName(lfp3_nf_field) join_obj.setTargetFieldName(lfp3_field) join_obj.setUsingMemoryCache(True) join_obj.setPrefix("lfp3_nf_") vlayer_lfp3.addJoin(join_obj) layer = { "type": "postgres", "title": _translate("VeriSO_V+D_FP3", "LFP3 ausserhalb " "Gemeinde", None), "featuretype": "t_lfp3_ausserhalb_gemeinde", "geom": "geometrie", "key": "ogc_fid", "sql": "", "readonly": True, "group": group, "style": "fixpunkte/lfp3ausserhalb.qml" } vlayer = self.layer_loader.load(layer) layer = { "type": "postgres", "title": _translate("VeriSO_V+D_FP3", "LFP3 pro TS", None), "featuretype": "t_lfp3_pro_ts", "key": "ogc_fid", "sql": "", "readonly": True, "group": group } vlayer_lfp3_pro_ts = self.layer_loader.load(layer) layer = { "type": "postgres", "title": _translate("VeriSO_V+D_FP3", "Gemeindegrenze", None), "featuretype": "gemeindegrenzen_gemeindegrenze", "geom": "geometrie", "key": "ogc_fid", "sql": "", "readonly": True, "group": group, "style": "global_qml/gemeindegrenze/gemgre_strichliert.qml" } gemgrelayer = self.layer_loader.load(layer) # Change map extent. # Bug (?) in QGIS: http://hub.qgis.org/issues/10980 # Closed for the lack of feedback. Upsi... # Still a problem? (sz / 2015-04-12) # sz / 2015-04-20: # Aaaah: still a problem. Some really strange combination of # checked/unchecked-order-of-layers-thing? # If wms is addes after gemgre then is scales (rect.scale(5))?! # So it seems that the last added layer HAS TO BE unchecked? # No not exactly. Only if a wms is added before? # rect.scale(5) has no effect? # I reopened the ticket / 2015-04-20 / sz if gemgrelayer: rect = gemgrelayer.extent() rect.scale(5) self.iface.mapCanvas().setExtent(rect) self.iface.mapCanvas().refresh() # Sometimes it does make much more sense # to zoom to maximal extent: # self.iface.mapCanvas().zoomToFullExtent() self.export_to_excel(vlayer_lfp3_pro_ts) except Exception: QApplication.restoreOverrideCursor() exc_type, exc_value, exc_traceback = sys.exc_info() self.message_bar.pushMessage("Error", str( traceback.format_exc(exc_traceback)), level=Qgis.Critical, duration=0) QApplication.restoreOverrideCursor()
def test_field_is_read_only(self): """ Test fieldIsReadOnly """ layer = createLayerWithOnePoint() # layer is not editable => all fields are read only self.assertTrue(QgsVectorLayerUtils.fieldIsReadOnly(layer, 0)) self.assertTrue(QgsVectorLayerUtils.fieldIsReadOnly(layer, 1)) layer.startEditing() self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 0)) self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 1)) field = QgsField('test', QVariant.String) layer.addAttribute(field) self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 0)) self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 1)) self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 2)) # simulate read-only field from provider field = QgsField('test2', QVariant.String) field.setReadOnly(True) layer.addAttribute(field) self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 0)) self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 1)) self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 2)) self.assertTrue(QgsVectorLayerUtils.fieldIsReadOnly(layer, 3)) layer.rollBack() layer.startEditing() # edit form config specifies read only form_config = layer.editFormConfig() form_config.setReadOnly(1, True) layer.setEditFormConfig(form_config) self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 0)) self.assertTrue(QgsVectorLayerUtils.fieldIsReadOnly(layer, 1)) form_config.setReadOnly(1, False) layer.setEditFormConfig(form_config) self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 0)) self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 1)) # joined field layer2 = QgsVectorLayer( "Point?field=fldtxt2:string&field=fldint:integer", "addfeat", "memory") join_info = QgsVectorLayerJoinInfo() join_info.setJoinLayer(layer2) join_info.setJoinFieldName('fldint') join_info.setTargetFieldName('fldint') join_info.setUsingMemoryCache(True) layer.addJoin(join_info) layer.updateFields() self.assertEqual([f.name() for f in layer.fields()], ['fldtxt', 'fldint', 'addfeat_fldtxt2']) self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 0)) self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 1)) # join layer is not editable self.assertTrue(QgsVectorLayerUtils.fieldIsReadOnly(layer, 2)) # make join editable layer.removeJoin(layer2.id()) join_info.setEditable(True) layer.addJoin(join_info) layer.updateFields() self.assertEqual([f.name() for f in layer.fields()], ['fldtxt', 'fldint', 'addfeat_fldtxt2']) # should still be read only -- the join layer itself is not editable self.assertTrue(QgsVectorLayerUtils.fieldIsReadOnly(layer, 2)) layer2.startEditing() self.assertFalse(QgsVectorLayerUtils.fieldIsReadOnly(layer, 2)) # but now we set a property on the join layer which blocks editing for the feature... form_config = layer2.editFormConfig() form_config.setReadOnly(0, True) layer2.setEditFormConfig(form_config) # should now be read only -- the joined layer edit form config prohibits edits self.assertTrue(QgsVectorLayerUtils.fieldIsReadOnly(layer, 2))