def get(self, request, **kwargs): # try to use qprof api # ==================== # try to load layer try: epp = EleProDTM.objects.get(pk=kwargs['eleprodtm_pk']) layer = epp.layers.filter(qgs_layer_id=kwargs['qgs_layer_id'])[0] dem = epp.dtm_layer except KeyError: # Case qgs_layer_id not submit raise APIException('No qgs_layer_id parameter into url') except ObjectDoesNotExist as e: raise APIException('DTM project object not found into DB') except IndexError as e: raise APIException('Layer not set into a profile project') # try to get qgis_layer qgis_project = get_qgs_project(dem.project.qgis_file.path) qgis_dem = get_qgis_layer(dem) qgis_layer = get_qgis_layer(layer) # get single feature feature = qgis_layer.getFeature(kwargs['fid']) geom = feature.geometry() if not geom: raise APIException('Fid not found into layer') if geom.isMultipart(): line = multipolyline_to_xytuple_list2( geom.asMultiPolyline()) # typedef QVector<QgsPolyline> # now it's a list of list of (x,y) tuples path_line = xytuple_l2_to_MultiLine(line).to_line() else: line = polyline_to_xytuple_list( geom.asPolyline()) # typedef QVector<QgsPointXY> path_line = xytuple_list_to_Line(line) multi_path_line = MultiLine([path_line ]).to_line().remove_coincident_points() # line resampled by sample distance resampled_line = multi_path_line.densify_2d_line(epp.dtm_delta) if qgis_layer.crs() != qgis_project.crs(): resampled_line = resampled_line.crs_project( qgis_layer.crs(), qgis_project.crs()) profile = topoline_from_dem( resampled_line, True, qgis_project.crs(), qgis_dem, QGisRasterParameters(*raster_qgis_params(qgis_dem)), epp.dtm_delta) self.results.update({'profile': profile}) return Response(self.results.results)
def apply_filter(self, request, metadata_layer, qgis_feature_request, view=None): """Apply the filter to the QGIS feature request or the layer's subset string Warning: if the filter alters the layer instance (for example by settings a subset string) make sure to restore the original state or to work on a clone. """ qgis_layer = metadata_layer.qgis_layer expression_text = None if FILTER_RELATIONONETOMANY_PARAM not in request.GET \ or request.GET[FILTER_RELATIONONETOMANY_PARAM] == '': return else: try: relation_id, parent_serverFid = request.GET[ FILTER_RELATIONONETOMANY_PARAM].split('|') except ValueError as e: logger.error('RelationOneToManyFilter: %s' % (e, )) return if not relation_id or not parent_serverFid: return # get QgsRelation object qgs_prj = get_qgs_project(view.layer.project.qgis_file.path) qgs_relation = qgs_prj.relationManager().relation(relation_id) if not qgs_relation.isValid(): return # get expression try: expression = expression_from_server_fids( [parent_serverFid], qgs_relation.referencedLayer().dataProvider()) feature = next(qgs_relation.referencedLayer().getFeatures( QgsFeatureRequest(QgsExpression(expression)))) expression_text = qgs_relation.getRelatedFeaturesFilter(feature) except StopIteration: logger.error( 'RelationOneToManyFilter: error finding related feature from expression' ) return if not expression_text: logger.error( 'RelationOneToManyFilter: empty related feature expression filter' ) return qgis_feature_request.combineFilterExpression(expression_text)
def apply_filter(self, request, qgis_layer, qgis_feature_request, view=None): """Apply the filter to the QGIS feature request or the layer's subset string Warning: if the filter alters the layer instance (for example by settings a subset string) make sure to restore the original state or to work on a clone. """ expression_text = None if FILTER_RELATIONONETOMANY_PARAM not in request.GET \ or request.GET[FILTER_RELATIONONETOMANY_PARAM] == '': return else: try: relation_id, parent_fid = request.GET[ FILTER_RELATIONONETOMANY_PARAM].split('|') except ValueError as e: logger.error('RelationOneToManyFilter: %s' % (e, )) return if not relation_id or not parent_fid: return # get QgsRelation object qgs_prj = get_qgs_project(view.layer.project.qgis_file.path) qgs_relation = qgs_prj.relationManager().relation(relation_id) if not qgs_relation.isValid(): return # get expression expression_text = qgs_relation.getRelatedFeaturesFilter( qgs_relation.referencedLayer().getFeature(int(parent_fid))) if not expression_text: return original_expression = qgis_feature_request.filterExpression( ) if qgis_feature_request is not None else None if original_expression is not None: qgis_feature_request.setFilterExpression( "({original_expression}) AND ({extra_expression})".format( original_expression=original_expression.expression(), extra_expression=expression_text)) else: qgis_feature_request.setFilterExpression(expression_text)
def test_filtertoken_api(self): """ Test vector layer api data with 'filtertoken' param """ cities = Layer.objects.get(project_id=self.project310.instance.pk, origname='cities10000eu') qgis_project = get_qgs_project(cities.project.qgis_file.path) qgis_layer = qgis_project.mapLayer(cities.qgs_layer_id) # create a token filter admin01 = self.test_user1 session_token = SessionTokenFilter.objects.create(user=admin01) session_filter = session_token.stf_layers.create( layer=cities, qgs_expr="ISO2_CODE = 'IT'") resp = json.loads( self._testApiCall('core-vector-api', [ 'data', 'qdjango', self.project310.instance.pk, cities.qgs_layer_id ], { 'filtertoken': session_token.token }).content) self.assertEqual(resp['vector']['count'], 1124) # update token filer session_filter.qgs_expr = "ISO2_CODE = 'XXXXX'" session_filter.save() resp = json.loads( self._testApiCall('core-vector-api', [ 'data', 'qdjango', self.project310.instance.pk, cities.qgs_layer_id ], { 'filtertoken': session_token.token }).content) self.assertEqual(resp['vector']['count'], 0) # submit a fake token/ filter token of other layer resp = json.loads( self._testApiCall('core-vector-api', [ 'data', 'qdjango', self.project310.instance.pk, cities.qgs_layer_id ], { 'filtertoken': 'xxxxxxxxxxxxxx' }).content) self.assertEqual(resp['vector']['count'], 8965)
def test_relationonetomany_api(self): """ Test relationonetomany filter """ cities = Layer.objects.get(project_id=self.project310.instance.pk, origname='cities10000eu') qgis_project = get_qgs_project(cities.project.qgis_file.path) qgis_layer = qgis_project.mapLayer(cities.qgs_layer_id) total_count = qgis_layer.featureCount() resp = json.loads( self._testApiCall('core-vector-api', [ 'data', 'qdjango', self.project310.instance.pk, cities.qgs_layer_id ], { FILTER_RELATIONONETOMANY_PARAM: '' }).content) self.assertEqual(resp['vector']['count'], total_count) # check filter by relations resp = json.loads( self._testApiCall( 'core-vector-api', [ 'data', 'qdjango', self.project310.instance.pk, cities.qgs_layer_id ], { FILTER_RELATIONONETOMANY_PARAM: 'cities1000_ISO2_CODE_countries__ISOCODE|18' }).content) qgs_request = QgsFeatureRequest() qgs_request.setFilterExpression('"ISO2_CODE" = \'IT\'') qgis_layer.selectByExpression( qgs_request.filterExpression().expression()) features = qgis_layer.getFeatures(qgs_request) self.assertEqual(resp['vector']['count'], len([f for f in features]))
def test_unique_request_api_param(self): """ Test 'unique' url request param for 'data' vector API """ cities = Layer.objects.get(project_id=self.project310.instance.pk, origname='cities10000eu') qgis_project = get_qgs_project(cities.project.qgis_file.path) qgis_layer = qgis_project.mapLayer(cities.qgs_layer_id) # check for only unique param total_count = len( qgis_layer.uniqueValues(qgis_layer.fields().indexOf('ISO2_CODE'))) resp = json.loads( self._testApiCall('core-vector-api', [ 'data', 'qdjango', self.project310.instance.pk, cities.qgs_layer_id ], { 'unique': 'ISO2_CODE' }).content) self.assertEqual(resp['count'], total_count) # check SuggestFilterBackend + FieldFilterBackend # ----------------------------------------------- resp = json.loads( self._testApiCall( 'core-vector-api', [ 'data', 'qdjango', self.project310.instance.pk, cities.qgs_layer_id ], { 'suggest': 'NAME|flo', 'field': 'ISO2_CODE|eq|IT', 'unique': 'ISO2_CODE' }).content) self.assertEqual(resp['count'], 1)
def test_server_filters_combination_api(self): """ Test server filter combination: i.e. FieldFilterBacked + SuggestFilterBackend """ cities = Layer.objects.get(project_id=self.project310.instance.pk, origname='cities10000eu') qgis_project = get_qgs_project(cities.project.qgis_file.path) qgis_layer = qgis_project.mapLayer(cities.qgs_layer_id) # check FieldFilterBacked # ----------------------- qgs_request = QgsFeatureRequest() qgs_request.setFilterExpression('"ISO2_CODE" = \'IT\'') total_count = len([f for f in qgis_layer.getFeatures(qgs_request)]) resp = json.loads( self._testApiCall('core-vector-api', [ 'data', 'qdjango', self.project310.instance.pk, cities.qgs_layer_id ], { 'field': 'ISO2_CODE|eq|IT' }).content) self.assertEqual(resp['vector']['count'], total_count) qgs_request = QgsFeatureRequest() qgs_request.setFilterExpression( '"ISO2_CODE" = \'IT\' OR "ISO2_CODE" = \'FR\'') total_count = len([f for f in qgis_layer.getFeatures(qgs_request)]) resp = json.loads( self._testApiCall('core-vector-api', [ 'data', 'qdjango', self.project310.instance.pk, cities.qgs_layer_id ], { 'field': 'ISO2_CODE|eq|IT|OR,ISO2_CODE|eq|FR' }).content) self.assertEqual(resp['vector']['count'], total_count) qgs_request = QgsFeatureRequest() qgs_request.setFilterExpression( '"ISO2_CODE" = \'IT\' AND "POPULATION" > 10000 OR "ISO2_CODE" = \'FR\'' ) total_count = len([f for f in qgis_layer.getFeatures(qgs_request)]) resp = json.loads( self._testApiCall( 'core-vector-api', [ 'data', 'qdjango', self.project310.instance.pk, cities.qgs_layer_id ], { 'field': 'ISO2_CODE|eq|IT|AND,POPULATION|gt|10000|OR,ISO2_CODE|eq|FR', }).content) self.assertEqual(resp['vector']['count'], total_count) qgs_request = QgsFeatureRequest() qgs_request.setFilterExpression('"NAME" LIKE \'%Flo%\'') total_count = len([f for f in qgis_layer.getFeatures(qgs_request)]) resp = json.loads( self._testApiCall('core-vector-api', [ 'data', 'qdjango', self.project310.instance.pk, cities.qgs_layer_id ], { 'field': 'NAME|like|Flo' }).content) self.assertEqual(resp['vector']['count'], total_count) qgs_request = QgsFeatureRequest() qgs_request.setFilterExpression('"NAME" ILIKE \'%flo%\'') total_count = len([f for f in qgis_layer.getFeatures(qgs_request)]) resp = json.loads( self._testApiCall('core-vector-api', [ 'data', 'qdjango', self.project310.instance.pk, cities.qgs_layer_id ], { 'field': 'NAME|ilike|flo' }).content) self.assertEqual(resp['vector']['count'], total_count) qgs_request = QgsFeatureRequest() qgs_request.setFilterExpression( '"ISO2_CODE" = \'IT\' AND "NAME" = \'Florence\'') total_count = len([f for f in qgis_layer.getFeatures(qgs_request)]) resp = json.loads( self._testApiCall('core-vector-api', [ 'data', 'qdjango', self.project310.instance.pk, cities.qgs_layer_id ], { 'field': 'ISO2_CODE|eq|IT,NAME|eq|Florence' }).content) self.assertEqual(resp['vector']['count'], total_count) # check SuggestFilterBackend # -------------------------- qgs_request = QgsFeatureRequest() qgs_request.setFilterExpression('"NAME" ILIKE \'%flo%\'') total_count = len([f for f in qgis_layer.getFeatures(qgs_request)]) resp = json.loads( self._testApiCall('core-vector-api', [ 'data', 'qdjango', self.project310.instance.pk, cities.qgs_layer_id ], { 'suggest': 'NAME|flo' }).content) self.assertEqual(resp['vector']['count'], total_count) # check SuggestFilterBackend + FieldFilterBackend # ----------------------------------------------- qgs_request = QgsFeatureRequest() qgs_request.setFilterExpression( '"NAME" ILIKE \'%flo%\' AND "ISO2_CODE" = \'IT\'') total_count = len([f for f in qgis_layer.getFeatures(qgs_request)]) resp = json.loads( self._testApiCall('core-vector-api', [ 'data', 'qdjango', self.project310.instance.pk, cities.qgs_layer_id ], { 'suggest': 'NAME|flo', 'field': 'ISO2_CODE|eq|IT' }).content) self.assertEqual(resp['vector']['count'], total_count) self.assertEqual(resp['vector']['count'], 2) qgs_request = QgsFeatureRequest() qgs_request.setFilterExpression( '"NAME" ILIKE \'%flo%\' AND "ISO2_CODE" = \'IT\' AND "NAME" = \'Florence\'' ) total_count = len([f for f in qgis_layer.getFeatures(qgs_request)]) resp = json.loads( self._testApiCall('core-vector-api', [ 'data', 'qdjango', self.project310.instance.pk, cities.qgs_layer_id ], { 'suggest': 'NAME|flo', 'field': 'ISO2_CODE|eq|IT,NAME|eq|Florence' }).content) self.assertEqual(resp['vector']['count'], total_count) self.assertEqual(resp['vector']['count'], 1)
def _get_relations(self, with_relations=[], flayer=None, ffactory=None, request=None, res={}): """ Check for relations adn add to res :param with_relations: relations id list :param source_layer: QgsVectorLayer instance of father :param res: result dict to send into response """ qgs_prj = get_qgs_project(flayer.project.qgis_file.path) relations = None for relation_id in with_relations: qgs_relation = qgs_prj.relationManager().relation(relation_id) if not qgs_relation.isValid(): logger.error(f'Relation with id {relation_id} is not valid.') continue csource_layer = qgs_relation.referencingLayer() clayer = flayer.project.layer_set.get( qgs_layer_id=csource_layer.id()) # get every qplotly active for child layer qplotlies = clayer.qplotlywidget_set.all() if len(qplotlies) == 0: continue if not relations: relations = {relation_id: []} else: relations.update({relation_id: []}) for qplotly in qplotlies: settings = QplotlySettings() if not settings.read_from_model(qplotly): logger.error( f'Error on load qlotly settings for layer pk {clayer.pk}.' ) continue factory = QplotlyFactoringRelation(settings, request=request, layer=clayer) factory.source_layer = csource_layer # create expression ffiltered_features = ffactory.source_layer.getFeatures( ffactory.qgsrequest) factory.set_father_features_expresion( qgs_relation=qgs_relation, ffiltered_features=ffiltered_features) factory.rebuild() relations[relation_id].append({ 'id': qplotly.pk, 'data': factory.trace }) if 'relations' not in res and relations: res.update({'relations': relations})