diff --git a/backend/gn_module_zh/blueprint.py b/backend/gn_module_zh/blueprint.py index 18a6b3c2..57b20e21 100644 --- a/backend/gn_module_zh/blueprint.py +++ b/backend/gn_module_zh/blueprint.py @@ -21,7 +21,7 @@ from geonature.utils.env import DB, ROOT_DIR, BACKEND_DIR from pypnnomenclature.models import TNomenclatures from pypnusershub.db.models import Organisme, User -from sqlalchemy import desc, func, text +from sqlalchemy import desc, func, text, select, update, delete from sqlalchemy.orm import aliased from utils_flask_sqla.generic import GenericQuery from utils_flask_sqla.response import json_resp_accept_empty_list, json_resp @@ -93,7 +93,7 @@ def get_zh(scope): coauthor = aliased(User, name="coauthor") coorganism = aliased(Organisme, name="coorganism") q = ( - DB.session.query(TZH) + select(TZH) .join(TNomenclatures, TZH.sdage) .join(User, TZH.authors) .join(coauthor, TZH.coauthors) @@ -109,6 +109,7 @@ def get_zh(scope): if request.is_json: q = main_search(q, request.json) + # q2 = main_search(q2, request.json) return get_all_zh( info_role=g.current_user, @@ -123,7 +124,7 @@ def get_zh(scope): def get_all_zh(info_role, query, limit, page, orderby=None, order="asc"): # try: # Pour obtenir le nombre de résultat de la requete sans le LIMIT - nb_results_without_limit = query.count() + nb_results_without_limit = DB.session.scalar(select(func.count()).select_from(query.subquery())) user = info_role user_cruved = get_user_cruved() @@ -151,7 +152,7 @@ def get_all_zh(info_role, query, limit, page, orderby=None, order="asc"): # Order by id because there can be ambiguity in order_by(col) depending # on the column so add on order_by id makes it clearer - data = query.order_by(TZH.id_zh).limit(limit).offset(page * limit).all() + data = DB.session.scalars(query.order_by(TZH.id_zh).limit(limit).offset(page * limit)).all() is_ref_geo = check_ref_geo_schema() featureCollection = [] @@ -336,8 +337,7 @@ def get_pbf(): SELECT ST_AsGeobuf(q, 'geom') as pbf FROM (SELECT id_zh, geom from pr_zh.t_zh tz) AS q; """ - query = DB.session.execute(sql) - row = query.first() + row = DB.session.execute(text(sql)).first() return Response(bytes(row["pbf"]) if row["pbf"] else bytes(), mimetype="application/protobuf") @@ -364,8 +364,7 @@ def get_pbf_complete(): 'bassin_versant', tz.bassin_versant) as json_arrays FROM pr_zh.atlas_app tz) AS q; """ - query = DB.session.execute(sql) - row = query.first() + row = DB.session.execute(text(sql)).first() return Response(bytes(row["pbf"]) if row["pbf"] else bytes(), mimetype="application/protobuf") @@ -385,8 +384,7 @@ def get_json(): ) AS feature FROM (SELECT * FROM pr_zh.atlas_app tz) inputs) features; """ - query = DB.session.execute(sql) - row = query.first() + row = DB.session.execute(text(sql)).first() return row["geojson"] @@ -396,7 +394,7 @@ def get_json(): def get_geometries(): """Get list of all zh geometries (contours)""" try: - if not DB.session.query(TZH).all(): + if not DB.session.execute(select(TZH)).all(): raise ZHApiError( message="no_geometry", details="Empty list of zh returned from get_zh_list db request", @@ -406,7 +404,7 @@ def get_geometries(): "geometry": zh.get_geofeature()["geometry"], "id_zh": zh.get_geofeature()["properties"]["id_zh"], } - for zh in DB.session.query(TZH).all() + for zh in DB.session.scalars(select(TZH)).all() ] except Exception as e: if e.__class__.__name__ == "ZHApiError": @@ -428,17 +426,14 @@ def get_ref_autocomplete(): params = request.args search_title = params.get("search_title") # search_title = 'MCD' - q = DB.session.query( - TReferences, - func.similarity(TReferences.title, search_title).label("idx_trgm"), - ) + q = select(TReferences, func.similarity(TReferences.title, search_title).label("idx_trgm")) search_title = search_title.replace(" ", "%") - q = q.filter(TReferences.title.ilike("%" + search_title + "%")).order_by(desc("idx_trgm")) + q = q.where(TReferences.title.ilike("%" + search_title + "%")).order_by(desc("idx_trgm")) limit = request.args.get("limit", 20) - data = q.limit(limit).all() + data = DB.session.execute(q.limit(limit)).all() if data: return [d[0].as_dict() for d in data] else: @@ -462,17 +457,16 @@ def get_file_list(id_zh): """get a list of the zh files contained in static repo""" try: # FIXME: to optimize... See relationships and lazy join with sqlalchemy - zh_uuid = DB.session.query(TZH).filter(TZH.id_zh == id_zh).one().zh_uuid - q_medias = ( - DB.session.query(TMedias, TNomenclatures.label_default) - .filter(TMedias.unique_id_media == zh_uuid) + zh_uuid = DB.session.scalar(select(TZH.zh_uuid).where(TZH.id_zh == id_zh)) + q_medias = DB.session.execute( + select(TMedias, TNomenclatures.label_default) .join( TNomenclatures, TNomenclatures.id_nomenclature == TMedias.id_nomenclature_media_type, ) + .where(TMedias.unique_id_media == zh_uuid) .order_by(TMedias.meta_update_date.desc()) - .all() - ) + ).all() res_media, image_medias = [], [] for media, media_type in q_medias: res_media.append(media) @@ -528,9 +522,12 @@ def post_main_pict(id_zh, id_media): """post main picture id in tzh""" try: # FIXME: after insert+after update on t_zh => update_date=dt.now() - DB.session.query(TZH).filter(TZH.id_zh == id_zh).update( - {TZH.main_pict_id: id_media, TZH.update_date: dt.now()} + stmt = ( + update(TZH) + .where(TZH.id_zh == id_zh) + .values(main_pict_id=id_media, update_date=dt.now()) ) + DB.session.execute(stmt) DB.session.commit() return ("", 204) except Exception as e: @@ -553,18 +550,16 @@ def post_main_pict(id_zh, id_media): @blueprint.route("/photos", methods=["GET"]) @json_resp def get_all_photos(id_zh: int): - q_medias = ( - DB.session.query(TZH.main_pict_id, TMedias.id_media, TMedias.media_path) + q_medias = DB.session.execute( + select(TZH.main_pict_id, TMedias.id_media, TMedias.media_path) .join(TZH, TZH.zh_uuid == TMedias.unique_id_media) .join( TNomenclatures, TNomenclatures.id_nomenclature == TMedias.id_nomenclature_media_type, ) .order_by(TMedias.meta_update_date.desc()) - .filter(TNomenclatures.label_default == "Photo") - .filter(TZH.id_zh == id_zh) - .all() - ) + .where(TNomenclatures.label_default == "Photo", TZH.id_zh == id_zh) + ).all() api_uri = urljoin( f"{config['API_ENDPOINT']}/", f"{blueprint.config['MODULE_CODE'].lower()}/{blueprint.config['file_path']}/", @@ -767,18 +762,18 @@ def deleteOneZh(id_zh): zhRepository = ZhRepository(TZH) # delete references - DB.session.query(CorZhRef).filter(CorZhRef.id_zh == id_zh).delete() + DB.session.execute(delete(CorZhRef).where(CorZhRef.id_zh == id_zh)) # delete criteres delim - id_lim_list = DB.session.query(TZH).filter(TZH.id_zh == id_zh).one().id_lim_list - DB.session.query(CorLimList).filter(CorLimList.id_lim_list == id_lim_list).delete() + id_lim_list = DB.session.execute(select(TZH.id_lim_list).where(TZH.id_zh == id_zh)).scalar_one() + DB.session.execute(delete(CorLimList).where(CorLimList.id_lim_list == id_lim_list)) # delete cor_zh_area - DB.session.query(CorZhArea).filter(CorZhArea.id_zh == id_zh).delete() + DB.session.execute(delete(CorZhArea).where(CorZhArea.id_zh == id_zh)) # delete files in TMedias and repos - zh_uuid = DB.session.query(TZH).filter(TZH.id_zh == id_zh).one().zh_uuid - q_medias = DB.session.query(TMedias).filter(TMedias.unique_id_media == zh_uuid).all() + zh_uuid = DB.session.execute(select(TZH.zh_uuid).where(TZH.id_zh == id_zh)).scalar_one() + q_medias = DB.session.scalars(select(TMedias).where(TMedias.unique_id_media == zh_uuid)).all() for media in q_medias: delete_file(media.id_media) @@ -803,9 +798,11 @@ def write_csv(id_zh): names = [] FILE_PATH = blueprint.config["file_path"] MODULE_NAME = blueprint.config["MODULE_CODE"].lower() - zh_code = DB.session.query(TZH).filter(TZH.id_zh == id_zh).one().code + zh_code = DB.session.scalar(select(TZH.code).where(TZH.id_zh == id_zh)) # author name - user = DB.session.query(User).filter(User.id_role == g.current_user.id_role).one() + user = DB.session.execute( + select(User).where(User.id_role == g.current_user.id_role) + ).scalar_one() author = user.prenom_role + " " + user.nom_role for i in ["vertebrates_view_name", "invertebrates_view_name", "flora_view_name"]: query = GenericQuery( @@ -813,7 +810,7 @@ def write_csv(id_zh): tableName=blueprint.config[i]["table_name"], schemaName=blueprint.config[i]["schema_name"], filters={"id_zh": id_zh, "orderby": "id_zh"}, - limit=-1, + limit=100, ) results = query.return_query().get("items", []) current_date = dt.now() @@ -864,8 +861,10 @@ def write_csv(id_zh): DB.session.flush() # update TMedias.media_path with media_filename - DB.session.query(TMedias).filter(TMedias.id_media == id_media).update( - {"media_path": str(media_path)} + DB.session.execute( + update(TMedias) + .where(TMedias.id_media == id_media) + .values(media_path=str(media_path)) ) DB.session.commit() @@ -924,41 +923,43 @@ def download(id_zh: int): @json_resp def departments(): query = ( - DB.session.query(LAreas) - .with_entities(LAreas.area_name, LAreas.area_code, LAreas.id_type, BibAreasTypes.type_code) + select(LAreas) + .with_only_columns( + LAreas.area_name, LAreas.area_code, LAreas.id_type, BibAreasTypes.type_code + ) .join(BibAreasTypes, LAreas.id_type == BibAreasTypes.id_type) - .filter(BibAreasTypes.type_code == "DEP") - .filter(LAreas.enable) + .where(BibAreasTypes.type_code == "DEP") + .where(LAreas.enable) .order_by(LAreas.area_code) ) - resp = query.all() + resp = DB.session.execute(query).all() return [{"code": r.area_code, "name": r.area_name} for r in resp] @blueprint.route("/communes", methods=["POST"]) @json_resp def get_area_from_department() -> dict: + # route utilisée ? code = request.json.get("code") if code: query = ( - DB.session.query(LiMunicipalities) - .with_entities(LiMunicipalities.id_area, LAreas.area_name, LAreas.area_code) + select(LiMunicipalities) + .with_only_columns(LiMunicipalities.id_area, LAreas.area_name, LAreas.area_code) .join(LAreas, LiMunicipalities.id_area == LAreas.id_area) - .filter(LiMunicipalities.insee_com.like("{}%".format(code))) - .filter(LAreas.enable) + .where(LiMunicipalities.insee_com.like("{}%".format(code))) + .where(LAreas.enable) + .order_by(LAreas.area_code) ) - query = query.order_by(LAreas.area_code) - resp = query.all() + resp = DB.session.execute(query).all() return [{"code": r.area_code, "name": r.area_name} for r in resp] - return [] @blueprint.route("/bassins", methods=["GET"]) @json_resp def bassins(): - query = DB.session.query(TRiverBasin).with_entities(TRiverBasin.id_rb, TRiverBasin.name) - resp = query.order_by(TRiverBasin.name).all() + query = select(TRiverBasin.id_rb, TRiverBasin.name).order_by(TRiverBasin.name) + resp = DB.session.execute(query).all() return [{"code": r.id_rb, "name": r.name} for r in resp] @@ -968,9 +969,8 @@ def get_hydro_zones_from_bassin() -> dict: code = request.json.get("code") if code: query = ( - DB.session.query(THydroArea) - .with_entities(THydroArea.id_hydro, THydroArea.name, TRiverBasin.id_rb) - .filter(TRiverBasin.id_rb == code) + select(THydroArea.id_hydro, THydroArea.name, TRiverBasin.id_rb) + .where(TRiverBasin.id_rb == code) .join( TRiverBasin, func.ST_Contains( @@ -978,9 +978,10 @@ def get_hydro_zones_from_bassin() -> dict: func.ST_SetSRID(THydroArea.geom, 4326), ), ) + .order_by(THydroArea.name) ) - resp = query.order_by(THydroArea.name).all() + resp = DB.session.execute(query).all() return [{"code": r.id_hydro, "name": r.name} for r in resp] return [] diff --git a/backend/gn_module_zh/forms.py b/backend/gn_module_zh/forms.py index 560081a8..a4970e62 100644 --- a/backend/gn_module_zh/forms.py +++ b/backend/gn_module_zh/forms.py @@ -9,6 +9,7 @@ from geonature.utils.env import DB from pypnnomenclature.models import TNomenclatures from sqlalchemy import and_, func +from sqlalchemy.sql import select, delete, update from .api_error import ZHApiError from .model.code import Code @@ -46,7 +47,7 @@ def update_tzh(data): - zh = DB.session.query(TZH).filter_by(id_zh=data["id_zh"]).first() + zh = DB.session.get(TZH, data["id_zh"]) for key, val in data.items(): if hasattr(TZH, key) and key != "id_zh": setattr(zh, key, val) @@ -85,23 +86,28 @@ def create_zh(form_data, info_role, zh_date, polygon, zh_area, ref_geo_referenti post_cor_zh_area( polygon, new_zh.id_zh, - DB.session.query(BibAreasTypes).filter(BibAreasTypes.type_code == "COM").one().id_type, + DB.session.execute( + select(BibAreasTypes.id_type).where(BibAreasTypes.type_code == "COM") + ).scalar_one(), ) # fill cor_zh_area for departements post_cor_zh_area( polygon, new_zh.id_zh, - DB.session.query(BibAreasTypes).filter(BibAreasTypes.type_code == "DEP").one().id_type, + DB.session.execute( + select(BibAreasTypes.id_type).where(BibAreasTypes.type_code == "DEP") + ).scalar_one(), ) # fill cor_zh_area for other geo referentials for ref in ref_geo_referentiels: post_cor_zh_area( polygon, new_zh.id_zh, - DB.session.query(BibAreasTypes) - .filter(BibAreasTypes.type_code == ref["type_code_ref_geo"]) - .one() - .id_type, + DB.session.execute( + select(BibAreasTypes.id_type).where( + BibAreasTypes.type_code == ref["type_code_ref_geo"] + ) + ).scalar_one(), ) # fill cor_zh_rb @@ -115,12 +121,11 @@ def create_zh(form_data, info_role, zh_date, polygon, zh_area, ref_geo_referenti new_zh.code = code.__repr__() new_zh.ef_area = total_cover # set default values - fct_delim_default_id = ( - DB.session.query(DefaultsNomenclaturesValues) - .filter(DefaultsNomenclaturesValues.mnemonique_type == "CRIT_DEF_ESP_FCT") - .one() - .id_nomenclature - ) + fct_delim_default_id = DB.session.execute( + select(DefaultsNomenclaturesValues.id_nomenclature).where( + DefaultsNomenclaturesValues.mnemonique_type == "CRIT_DEF_ESP_FCT" + ) + ).scalar_one() post_fct_delim(new_zh.id_zh, [fct_delim_default_id]) @@ -168,28 +173,27 @@ def post_cor_zh_area(polygon, id_zh, id_type): # try: elements = [ getattr(element, "id_area") - for element in DB.session.query(LAreas) - .filter( - LAreas.geom.ST_Intersects( - func.ST_Transform(func.ST_SetSRID(func.ST_AsText(polygon), 4326), 2154) + for element in DB.session.scalars( + select(LAreas) + .where( + LAreas.geom.ST_Intersects( + func.ST_Transform(func.ST_SetSRID(func.ST_AsText(polygon), 4326), 2154) + ) ) - ) - .filter(LAreas.id_type == id_type) - .all() + .where(LAreas.id_type == id_type) + ).all() ] for element in elements: # if 'Communes', % of zh in the municipality must be calculated if id_type == CorZhArea.get_id_type("Communes"): - municipality_geom = getattr( - DB.session.query(LAreas).filter(LAreas.id_area == element).first(), "geom" + municipality_geom = getattr(DB.session.get(LAreas, element), "geom") + polygon_2154 = DB.session.scalar( + select(func.ST_Transform(func.ST_SetSRID(func.ST_AsText(polygon), 4326), 2154)) + ) + intersect_area = DB.session.scalar( + select(func.ST_Area(func.ST_Intersection(municipality_geom, polygon_2154))) ) - polygon_2154 = DB.session.query( - func.ST_Transform(func.ST_SetSRID(func.ST_AsText(polygon), 4326), 2154) - ).scalar() - intersect_area = DB.session.query( - func.ST_Area(func.ST_Intersection(municipality_geom, polygon_2154)) - ).scalar() - municipality_area = DB.session.query(func.ST_Area(municipality_geom)).scalar() + municipality_area = DB.session.scalar(select(func.ST_Area(municipality_geom))) cover = math.ceil((intersect_area * 100) / municipality_area) if cover > 100: cover = 100 @@ -280,11 +284,10 @@ def update_zh_tab0(form_data, polygon, area, info_role, zh_date, geo_refs): is_geom_new = check_polygon(polygon, form_data["id_zh"]) # update pr_zh.cor_lim_list - id_lim_list, ef_area = ( - DB.session.query(TZH.id_lim_list, TZH.ef_area).filter(TZH.id_zh == form_data["id_zh"]).one() - ) + id_lim_list = DB.session.get(TZH, form_data["id_zh"]).id_lim_list + ef_area = DB.session.get(TZH, form_data["id_zh"]).ef_area - DB.session.query(CorLimList).filter(CorLimList.id_lim_list == id_lim_list).delete() + DB.session.execute(delete(CorLimList).where(CorLimList.id_lim_list == id_lim_list)) post_cor_lim_list(id_lim_list, form_data["critere_delim"]) if is_geom_new: @@ -294,17 +297,19 @@ def update_zh_tab0(form_data, polygon, area, info_role, zh_date, geo_refs): ef_area = update_cor_zh_fct_area(form_data["geom"]["geometry"], form_data["id_zh"]) # update zh : fill pr_zh.t_zh - DB.session.query(TZH).filter(TZH.id_zh == form_data["id_zh"]).update( - { - TZH.main_name: form_data["main_name"], - TZH.id_org: form_data["id_org"], - TZH.update_author: info_role.id_role, - TZH.update_date: zh_date, - TZH.id_sdage: form_data["sdage"], - TZH.geom: polygon, - TZH.area: area, - TZH.ef_area: ef_area, - } + DB.session.execute( + update(TZH) + .where(TZH.id_zh == form_data["id_zh"]) + .values( + main_name=form_data["main_name"], + id_org=form_data["id_org"], + update_author=info_role.id_role, + update_date=zh_date, + id_sdage=form_data["sdage"], + geom=polygon, + area=area, + ef_area=ef_area, + ) ) DB.session.flush() @@ -324,7 +329,12 @@ def update_zh_tab0(form_data, polygon, area, info_role, zh_date, geo_refs): def check_polygon(polygon, id_zh): try: - if polygon != str(DB.session.query(TZH.geom).filter(TZH.id_zh == id_zh).one()[0]).upper(): + if ( + polygon + != str( + DB.session.execute(select(TZH.geom).where(TZH.id_zh == id_zh)).scalar_one() + ).upper() + ): return True return False except Exception as e: @@ -336,26 +346,31 @@ def check_polygon(polygon, id_zh): def update_cor_zh_area(polygon, id_zh, geo_refs): try: - DB.session.query(CorZhArea).filter(CorZhArea.id_zh == id_zh).delete() + DB.session.execute(delete(CorZhArea).where(CorZhArea.id_zh == id_zh)) post_cor_zh_area( polygon, id_zh, - DB.session.query(BibAreasTypes).filter(BibAreasTypes.type_code == "COM").one().id_type, + DB.session.execute( + select(BibAreasTypes.id_type).where(BibAreasTypes.type_code == "COM") + ).scalar_one(), ) post_cor_zh_area( polygon, id_zh, - DB.session.query(BibAreasTypes).filter(BibAreasTypes.type_code == "DEP").one().id_type, + DB.session.execute( + select(BibAreasTypes.id_type).where(BibAreasTypes.type_code == "DEP") + ).scalar_one(), ) # fill cor_zh_area for other geo referentials for ref in geo_refs: post_cor_zh_area( polygon, id_zh, - DB.session.query(BibAreasTypes) - .filter(BibAreasTypes.type_code == ref["type_code_ref_geo"]) - .one() - .id_type, + DB.session.execute( + select(BibAreasTypes.id_type).where( + BibAreasTypes.type_code == ref["type_code_ref_geo"] + ) + ).scalar_one(), ) except Exception as e: if e.__class__.__name__ == "DataError": @@ -372,17 +387,17 @@ def update_cor_zh_area(polygon, id_zh, geo_refs): def update_cor_zh_rb(geom, id_zh): - DB.session.query(CorZhRb).filter(CorZhRb.id_zh == id_zh).delete() + DB.session.execute(delete(CorZhRb).where(CorZhRb.id_zh == id_zh)) post_cor_zh_rb(geom, id_zh) def update_cor_zh_hydro(geom, id_zh): - DB.session.query(CorZhHydro).filter(CorZhHydro.id_zh == id_zh).delete() + DB.session.execute(delete(CorZhHydro).where(CorZhHydro.id_zh == id_zh)) post_cor_zh_hydro(geom, id_zh) def update_cor_zh_fct_area(geom, id_zh): - DB.session.query(CorZhFctArea).filter(CorZhFctArea.id_zh == id_zh).delete() + DB.session.execute(delete(CorZhFctArea).where(CorZhFctArea.id_zh == id_zh)) return post_cor_zh_fct_area(geom, id_zh) @@ -391,7 +406,7 @@ def update_cor_zh_fct_area(geom, id_zh): def update_refs(form_data): try: - DB.session.query(CorZhRef).filter(CorZhRef.id_zh == form_data["id_zh"]).delete() + DB.session.execute(delete(CorZhRef).where(CorZhRef.id_zh == form_data["id_zh"])) for ref in form_data["id_references"]: DB.session.add(CorZhRef(id_zh=form_data["id_zh"], id_ref=ref)) DB.session.flush() @@ -436,7 +451,7 @@ def post_activities(id_zh, activities): def update_activities(id_zh, activities): try: # delete cascade t_activity and cor_impact_list with id_zh - DB.session.query(TActivity).filter(TActivity.id_zh == id_zh).delete() + DB.session.execute(delete(TActivity).where(TActivity.id_zh == id_zh)) # post new activities post_activities(id_zh, activities) except Exception as e: @@ -455,7 +470,7 @@ def update_activities(id_zh, activities): def update_corine_biotopes(id_zh, corine_biotopes): try: - DB.session.query(CorZhCb).filter(CorZhCb.id_zh == id_zh).delete() + DB.session.execute(delete(CorZhCb).where(CorZhCb.id_zh == id_zh)) post_corine_biotopes(id_zh, corine_biotopes) except Exception as e: if e.__class__.__name__ == "DataError": @@ -479,7 +494,7 @@ def post_corine_biotopes(id_zh, corine_biotopes): def update_corine_landcover(id_zh, ids_cover): try: - DB.session.query(CorZhCorineCover).filter(CorZhCorineCover.id_zh == id_zh).delete() + DB.session.execute(delete(CorZhCorineCover).where(CorZhCorineCover.id_zh == id_zh)) post_corine_landcover(id_zh, ids_cover) except Exception as e: if e.__class__.__name__ == "DataError": @@ -506,10 +521,8 @@ def post_corine_landcover(id_zh, ids_cover): def update_delim(id_zh, criteria): try: - uuid_lim_list = ( - DB.session.query(TZH.id_lim_list).filter(TZH.id_zh == id_zh).one().id_lim_list - ) - DB.session.query(CorLimList).filter(CorLimList.id_lim_list == uuid_lim_list).delete() + uuid_lim_list = DB.session.get(TZH, id_zh).id_lim_list + DB.session.execute(delete(CorLimList).where(CorLimList.id_lim_list == uuid_lim_list)) post_delim(uuid_lim_list, criteria) except Exception as e: if e.__class__.__name__ == "DataError": @@ -533,7 +546,7 @@ def post_delim(uuid_lim, criteria): def update_fct_delim(id_zh, criteria): try: - DB.session.query(CorZhLimFs).filter(CorZhLimFs.id_zh == id_zh).delete() + DB.session.execute(delete(CorZhLimFs).where(CorZhLimFs.id_zh == id_zh)) post_fct_delim(id_zh, criteria) except Exception as e: if e.__class__.__name__ == "DataError": @@ -560,7 +573,7 @@ def post_fct_delim(id_zh, criteria): def update_outflow(id_zh, outflows): try: - DB.session.query(TOutflow).filter(TOutflow.id_zh == id_zh).delete() + DB.session.execute(delete(TOutflow).where(TOutflow.id_zh == id_zh)) post_outflow(id_zh, outflows) except Exception as e: if e.__class__.__name__ == "DataError": @@ -591,7 +604,7 @@ def post_outflow(id_zh, outflows): def update_inflow(id_zh, inflows): try: - DB.session.query(TInflow).filter(TInflow.id_zh == id_zh).delete() + DB.session.execute(select(TInflow).where(TInflow.id_zh == id_zh)) post_inflow(id_zh, inflows) except Exception as e: if e.__class__.__name__ == "DataError": @@ -643,9 +656,13 @@ def update_functions(id_zh, functions, function_type): nomenclature.id_nomenclature for nomenclature in Nomenclatures.get_nomenclature_info(function_type) ] - DB.session.query(TFunctions).filter(TFunctions.id_zh == id_zh).filter( - TFunctions.id_function.in_(id_function_list) - ).delete(synchronize_session="fetch") + stmt = ( + delete(TFunctions) + .where(TFunctions.id_zh == id_zh) + .where(TFunctions.id_function.in_(id_function_list)) + .execution_options(synchronize_session="fetch") + ) + DB.session.execute(stmt) post_functions(id_zh, functions) except Exception as e: if e.__class__.__name__ == "DataError": @@ -664,7 +681,7 @@ def update_functions(id_zh, functions, function_type): def update_hab_heritages(id_zh, hab_heritages): try: # delete cascade t_hab_heritages - DB.session.query(THabHeritage).filter(THabHeritage.id_zh == id_zh).delete() + DB.session.execute(delete(THabHeritage).where(THabHeritage.id_zh == id_zh)) # post new hab_heritages post_hab_heritages(id_zh, hab_heritages) except Exception as e: @@ -699,7 +716,7 @@ def post_hab_heritages(id_zh, hab_heritages): def update_ownerships(id_zh, ownerships): try: - DB.session.query(TOwnership).filter(TOwnership.id_zh == id_zh).delete() + DB.session.execute(delete(TOwnership).where(TOwnership.id_zh == id_zh)) post_ownerships(id_zh, ownerships) except Exception as e: if e.__class__.__name__ == "DataError": @@ -725,9 +742,9 @@ def post_ownerships(id_zh, ownerships): def update_managements(id_zh, managements): try: - DB.session.query(TManagementStructures).filter( - TManagementStructures.id_zh == id_zh - ).delete() + DB.session.execute( + delete(TManagementStructures).where(TManagementStructures.id_zh == id_zh) + ) # verifier si suppression en cascade ok dans TManagementPlans post_managements(id_zh, managements) except Exception as e: @@ -753,15 +770,14 @@ def post_managements(id_zh, managements): DB.session.add( TManagementPlans( id_nature=plan["id_nature"], - id_structure=DB.session.query(TManagementStructures) - .filter( - and_( - TManagementStructures.id_zh == id_zh, - TManagementStructures.id_org == management["structure"], + id_structure=DB.session.execute( + select(TManagementStructures.id_structure).where( + and_( + TManagementStructures.id_zh == id_zh, + TManagementStructures.id_org == management["structure"], + ) ) - ) - .one() - .id_structure, + ).scalar_one(), plan_date=datetime.datetime.strptime(plan["plan_date"], "%d/%m/%Y"), duration=plan["duration"], remark=plan["remark"], @@ -772,7 +788,7 @@ def post_managements(id_zh, managements): def update_instruments(id_zh, instruments): try: - DB.session.query(TInstruments).filter(TInstruments.id_zh == id_zh).delete() + DB.session.execute(delete(TInstruments).where(TInstruments.id_zh == id_zh)) post_instruments(id_zh, instruments) except Exception as e: if e.__class__.__name__ == "DataError": @@ -804,7 +820,7 @@ def post_instruments(id_zh, instruments): def update_protections(id_zh, protections): try: - DB.session.query(CorZhProtection).filter(CorZhProtection.id_zh == id_zh).delete() + DB.session.execute(select(CorZhProtection).where(CorZhProtection.id_zh == id_zh)) post_protections(id_zh, protections) except Exception as e: if e.__class__.__name__ == "DataError": @@ -824,10 +840,11 @@ def post_protections(id_zh, protections): for protection in protections: DB.session.add( CorZhProtection( - id_protection=DB.session.query(CorProtectionLevelType) - .filter(CorProtectionLevelType.id_protection_status == protection) - .one() - .id_protection, + id_protection=DB.session.execute( + select(CorProtectionLevelType.id_protection).where( + CorProtectionLevelType.id_protection_status == protection + ) + ).scalar_one(), id_zh=id_zh, ) ) @@ -837,15 +854,17 @@ def post_protections(id_zh, protections): def update_zh_tab6(data): try: is_other_inventory = data["is_other_inventory"] - DB.session.query(TZH).filter(TZH.id_zh == data["id_zh"]).update( - { - TZH.update_author: data["update_author"], - TZH.update_date: data["update_date"], - TZH.is_other_inventory: is_other_inventory, - TZH.remark_is_other_inventory: ( + DB.session.execute( + update(TZH) + .where(TZH.id_zh == data["id_zh"]) + .values( + update_author=data["update_author"], + update_date=data["update_date"], + is_other_inventory=is_other_inventory, + remark_is_other_inventory=( data["remark_is_other_inventory"] if is_other_inventory else None ), - } + ) ) DB.session.flush() except Exception as e: @@ -864,7 +883,7 @@ def update_zh_tab6(data): def update_urban_docs(id_zh, urban_docs): try: - DB.session.query(TUrbanPlanningDocs).filter(TUrbanPlanningDocs.id_zh == id_zh).delete() + DB.session.execute(delete(TUrbanPlanningDocs).where(TUrbanPlanningDocs.id_zh == id_zh)) post_urban_docs(id_zh, urban_docs) except Exception as e: if e.__class__.__name__ == "DataError": @@ -882,12 +901,11 @@ def update_urban_docs(id_zh, urban_docs): def post_urban_docs(id_zh, urban_docs): for urban_doc in urban_docs: - id_doc_type = ( - DB.session.query(CorUrbanTypeRange) - .filter(CorUrbanTypeRange.id_cor == urban_doc["id_urban_type"][0]["id_cor"]) - .one() - .id_doc_type - ) + id_doc_type = DB.session.execute( + select(CorUrbanTypeRange.id_doc_type).where( + CorUrbanTypeRange.id_cor == urban_doc["id_urban_type"][0]["id_cor"] + ) + ).scalar_one() uuid_doc = uuid.uuid4() DB.session.add( TUrbanPlanningDocs( @@ -910,7 +928,7 @@ def post_urban_docs(id_zh, urban_docs): def update_actions(id_zh, actions): try: # delete cascade actions - DB.session.query(TActions).filter(TActions.id_zh == id_zh).delete() + DB.session.execute(select(TActions).where(TActions.id_zh == id_zh)) # post new actions post_actions(id_zh, actions) except Exception as e: @@ -945,7 +963,9 @@ def post_actions(id_zh, actions): def post_file_info(id_zh, title, author, description, extension, media_path=None): try: - unique_id_media = DB.session.query(TZH).filter(TZH.id_zh == int(id_zh)).one().zh_uuid + unique_id_media = DB.session.execute( + select(TZH.zh_uuid).where(TZH.id_zh == int(id_zh)) + ).scalar_one() uuid_attached_row = uuid.uuid4() if extension == ".pdf": mnemo = "PDF" @@ -953,23 +973,17 @@ def post_file_info(id_zh, title, author, description, extension, media_path=None mnemo = "Tableur" else: mnemo = "Photo" - id_nomenclature_media_type = ( - DB.session.query(TNomenclatures) - .filter(TNomenclatures.mnemonique == mnemo) - .one() - .id_nomenclature - ) - id_table_location = ( - DB.session.query(BibTablesLocation) - .filter( + id_nomenclature_media_type = DB.session.execute( + select(TNomenclatures.id_nomenclature).where(TNomenclatures.mnemonique == mnemo) + ).scalar_one() + id_table_location = DB.session.execute( + select(BibTablesLocation.id_table_location).where( and_( BibTablesLocation.schema_name == "pr_zh", BibTablesLocation.table_name == "t_zh", ) ) - .one() - .id_table_location - ) + ).scalar_one() post_date = datetime.datetime.now() DB.session.add( TMedias( @@ -987,12 +1001,9 @@ def post_file_info(id_zh, title, author, description, extension, media_path=None ) ) DB.session.commit() - id_media = ( - DB.session.query(TMedias) - .filter(TMedias.uuid_attached_row == uuid_attached_row) - .one() - .id_media - ) + id_media = DB.session.execute( + select(TMedias.id_media).where(TMedias.uuid_attached_row == uuid_attached_row) + ).scalar_one() return id_media except Exception as e: if e.__class__.__name__ == "DataError": @@ -1006,31 +1017,32 @@ def post_file_info(id_zh, title, author, description, extension, media_path=None def patch_file_info(id_zh, id_media, title, author, description): try: - unique_id_media = DB.session.query(TZH).filter(TZH.id_zh == int(id_zh)).one().zh_uuid + unique_id_media = DB.session.execute( + select(TZH.zh_uuid).where(TZH.id_zh == int(id_zh)) + ).scalar_one() uuid_attached_row = uuid.uuid4() - id_table_location = ( - DB.session.query(BibTablesLocation) - .filter( + id_table_location = DB.session.execute( + select(BibTablesLocation.id_table_location).where( and_( BibTablesLocation.schema_name == "pr_zh", BibTablesLocation.table_name == "t_zh", ) ) - .one() - .id_table_location - ) + ).scalar_one() post_date = datetime.datetime.now() - DB.session.query(TMedias).filter(TMedias.id_media == id_media).update( - { - "unique_id_media": unique_id_media, - "id_table_location": id_table_location, - "uuid_attached_row": uuid_attached_row, - "title_fr": title, - "author": author, - "description_fr": description, - "is_public": True, - "meta_update_date": str(post_date), - } + DB.session.execute( + update(TMedias) + .where(TMedias.id_media == id_media) + .values( + unique_id_media=unique_id_media, + id_table_location=id_table_location, + uuid_attached_row=uuid_attached_row, + title_fr=title, + author=author, + description_fr=description, + is_public=True, + meta_update_date=str(post_date), + ) ) DB.session.flush() except exc.DataError as e: @@ -1051,14 +1063,13 @@ def update_file_extension(id_media, extension): mnemo = "Tableur" else: mnemo = "Photo" - id_nomenclature_media_type = ( - DB.session.query(TNomenclatures) - .filter(TNomenclatures.mnemonique == mnemo) - .one() - .id_nomenclature - ) - DB.session.query(TMedias).filter(TMedias.id_media == id_media).update( - {"id_nomenclature_media_type": id_nomenclature_media_type} + id_nomenclature_media_type = DB.session.execute( + select(TNomenclatures.id_nomenclature).where(TNomenclatures.mnemonique == mnemo) + ).scalar_one() + DB.session.execute( + update(TMedias) + .where(TMedias.id_media == id_media) + .values(id_nomenclature_media_type=id_nomenclature_media_type) ) DB.session.flush() except exc.DataError as e: @@ -1073,12 +1084,11 @@ def update_file_extension(id_media, extension): def post_note(id_zh, cor_rule_id, note, attribute_id, note_type_id): try: - element = ( - DB.session.query(CorZhNotes) - .filter(CorZhNotes.id_zh == id_zh) - .filter(CorZhNotes.cor_rule_id == cor_rule_id) - .first() - ) + element = DB.session.scalars( + select(CorZhNotes) + .where(CorZhNotes.id_zh == id_zh) + .where(CorZhNotes.cor_rule_id == cor_rule_id) + ).first() if element: if element.note != note: element.note = note diff --git a/backend/gn_module_zh/geometry.py b/backend/gn_module_zh/geometry.py index b9429a5f..b8c92d1c 100644 --- a/backend/gn_module_zh/geometry.py +++ b/backend/gn_module_zh/geometry.py @@ -3,6 +3,7 @@ from geoalchemy2.shape import to_shape from geonature.utils.env import DB from sqlalchemy import func +from sqlalchemy.sql import select, func from werkzeug.exceptions import BadRequest from .api_error import ZHApiError @@ -15,47 +16,50 @@ def set_geom(geometry, id_zh=None): if not id_zh: id_zh = 0 # SetSRID for POSTGIS < 3.0 compat - # select only already existing ZH geometries which intersect with the new ZH geometry - q_zh = ( - DB.session.query(TZH) - .filter( + q_zh = DB.session.scalars( + select(TZH) + .where( func.ST_Intersects( func.ST_GeogFromWKB(func.ST_AsEWKB(TZH.geom)), func.ST_GeogFromWKB(func.ST_AsEWKB(str(geometry))), ) ) - .filter( + .where( func.ST_Touches( func.ST_GeomFromWKB(func.ST_AsEWKB(TZH.geom), 4326), func.ST_GeomFromWKB(func.ST_AsEWKB(str(geometry)), 4326), ) == False ) - .all() - ) + ).all() is_intersected = False + polygon = DB.session.scalar( + select(func.ST_SetSRID(func.ST_GeomFromGeoJSON(str(geometry)), 4326)) + ) for zh in q_zh: if zh.id_zh != id_zh: - zh_geom = DB.session.query(func.ST_GeogFromWKB(func.ST_AsEWKB(zh.geom))).scalar() - polygon_geom = DB.session.query( - func.ST_GeogFromWKB(func.ST_AsEWKB(str(geometry))) - ).scalar() - if DB.session.query(func.ST_Intersects(polygon_geom, zh_geom)).scalar(): - if DB.session.query( - func.ST_GeometryType(func.ST_Intersection(zh_geom, polygon_geom, 0.1)) - ).scalar() not in ["ST_LineString", "ST_MultiLineString"]: + zh_geom = DB.session.scalar(select(func.ST_GeogFromWKB(func.ST_AsEWKB(zh.geom)))) + polygon_geom = DB.session.scalar( + select(func.ST_GeogFromWKB(func.ST_AsEWKB(str(geometry)))) + ) + if DB.session.scalar(select(func.ST_Intersects(polygon_geom, zh_geom))): + if DB.session.scalar( + select(func.ST_GeometryType(func.ST_Intersection(zh_geom, polygon_geom, 0.1))) + ) not in ["ST_LineString", "ST_MultiLineString"]: is_intersected = True - if DB.session.query( - func.ST_Contains( - zh_geom, - polygon_geom, + if DB.session.scalar( + select( + func.ST_Contains( + zh_geom, + polygon_geom, + ) ) - ).scalar(): + ): raise BadRequest("La ZH est entièrement dans une ZH existante") # TODO: not detected if contained entirely in 2 or more ZH polygons - polygon = DB.session.query(func.ST_Difference(polygon_geom, zh_geom)).scalar() + polygon = DB.session.scalar(select(func.ST_Difference(polygon_geom, zh_geom))) return {"polygon": polygon, "is_intersected": is_intersected} @@ -63,9 +67,9 @@ def set_area(geom): # unit : ha return round( ( - DB.session.query( - func.ST_Area(func.ST_GeomFromText(func.ST_AsText(geom["polygon"])), False) - ).scalar() + DB.session.scalar( + select(func.ST_Area(func.ST_GeomFromText(func.ST_AsText(geom["polygon"])), False)) + ) ) / 10000, 2, @@ -76,23 +80,25 @@ def get_main_rb(query: list) -> int: rb_id = None area = 0 for q_ in query: - zh_polygon = ( - DB.session.query(TZH.geom).filter(TZH.id_zh == getattr(q_, "id_zh")).first().geom + zh_polygon = DB.session.execute( + select(TZH.geom).where(TZH.id_zh == getattr(q_, "id_zh")).first() ) - rb_polygon = ( - DB.session.query(CorZhRb, TRiverBasin) + rb_polygon = DB.session.execute( + select(TRiverBasin.geom) .join(TRiverBasin, TRiverBasin.id_rb == CorZhRb.id_rb) - .filter(TRiverBasin.id_rb == getattr(q_, "id_rb")) + .where(TRiverBasin.id_rb == getattr(q_, "id_rb")) .first() - .TRiverBasin.geom ) - intersection = DB.session.query( - func.ST_Intersection( - func.ST_GeomFromText(func.ST_AsText(zh_polygon)), - func.ST_GeomFromText(func.ST_AsText(rb_polygon)), + + intersection = DB.session.scalar( + select( + func.ST_Intersection( + func.ST_GeomFromText(func.ST_AsText(zh_polygon)), + func.ST_GeomFromText(func.ST_AsText(rb_polygon)), + ) ) - ).scalar() - if DB.session.query(func.ST_Area(intersection, False)).scalar() > area: - area = DB.session.query(func.ST_Area(intersection, False)).scalar() + ) + if DB.session.scalar(select(func.ST_Area(intersection, False))) > area: + area = DB.session.scalar(select(func.ST_Area(intersection, False))) rb_id = getattr(q_, "id_rb") return rb_id diff --git a/backend/gn_module_zh/hierarchy.py b/backend/gn_module_zh/hierarchy.py index 4cd861dd..d1a0de7a 100644 --- a/backend/gn_module_zh/hierarchy.py +++ b/backend/gn_module_zh/hierarchy.py @@ -6,6 +6,7 @@ from geonature.utils.env import DB from pypnnomenclature.models import BibNomenclaturesTypes, TNomenclatures from sqlalchemy import and_ +from sqlalchemy.sql import select from sqlalchemy.orm.exc import NoResultFound from utils_flask_sqla.generic import GenericQuery @@ -53,10 +54,9 @@ def __init__(self, id_zh, rb_id, abb): def __get_rule_id(self, abb): try: - return getattr( - DB.session.query(TRules).filter(TRules.abbreviation == abb).one(), - "rule_id", - ) + return DB.session.execute( + select(TRules.rule_id).where(TRules.abbreviation == abb) + ).scalar_one() except Exception as e: exc_type, value, tb = sys.exc_info() raise ZHApiError( @@ -68,16 +68,14 @@ def __get_rule_id(self, abb): def __is_rb_rule(self): try: - q_rule = ( - DB.session.query(CorRbRules) - .filter( + q_rule = DB.session.scalars( + select(CorRbRules).where( and_( CorRbRules.rb_id == self.rb_id, CorRbRules.rule_id == self.rule_id, ) ) - .first() - ) + ).first() if q_rule: return True return False @@ -93,17 +91,14 @@ def __is_rb_rule(self): def __get_cor_rule_id(self): try: if self.active: - return getattr( - DB.session.query(CorRbRules) - .filter( + return DB.session.execute( + select(CorRbRules.cor_rule_id).where( and_( CorRbRules.rb_id == self.rb_id, CorRbRules.rule_id == self.rule_id, ) ) - .one(), - "cor_rule_id", - ) + ).scalar_one() except Exception as e: exc_type, value, tb = sys.exc_info() raise ZHApiError( @@ -114,27 +109,24 @@ def __get_cor_rule_id(self): DB.session.close() def __get_id_nomenc(self, id_type: int, cd_nomenc: str) -> int: - return getattr( - DB.session.query(TNomenclatures) - .filter( + return DB.session.scalars( + select(TNomenclatures.id_nomenclature).where( and_( TNomenclatures.id_type == id_type, TNomenclatures.cd_nomenclature == cd_nomenc, ) ) - .first(), - "id_nomenclature", - None, - ) + ).first() def __get_nomencs(self, abb, cat=None): cat_id = self.__get_id_nomenc(self.__get_id_type("HIERARCHY"), cat) return [ getattr(q_.CorRuleNomenc, "nomenc_id") - for q_ in DB.session.query(CorRuleNomenc, TRules) - .join(TRules) - .filter(and_(TRules.abbreviation == abb, CorRuleNomenc.qualif_id == cat_id)) - .all() + for q_ in DB.session.execute( + select(CorRuleNomenc, TRules) + .join(TRules) + .where(and_(TRules.abbreviation == abb, CorRuleNomenc.qualif_id == cat_id)) + ).all() ] def __get_nomenc_ids(self): @@ -160,42 +152,38 @@ def __get_qualif_cat7(self): try: id_nomenc = self.__get_qualif_val() if ( - getattr( - DB.session.query(TNomenclatures) - .filter(TNomenclatures.id_nomenclature == id_nomenc) - .one(), - "cd_nomenclature", - ) + DB.session.execute( + select(TNomenclatures.cd_nomenclature).where( + TNomenclatures.id_nomenclature == id_nomenc + ) + ).scalar_one() == "0" ): return self.__get_id_nomenc(self.__get_id_type("HIERARCHY"), "NE") if ( - getattr( - DB.session.query(TNomenclatures) - .filter(TNomenclatures.id_nomenclature == id_nomenc) - .one(), - "cd_nomenclature", - ) + DB.session.execute( + select(TNomenclatures.cd_nomenclature).where( + TNomenclatures.id_nomenclature == id_nomenc + ) + ).scalar_one() == "1" ): return self.__get_id_nomenc(self.__get_id_type("HIERARCHY"), "bon") if ( - getattr( - DB.session.query(TNomenclatures) - .filter(TNomenclatures.id_nomenclature == id_nomenc) - .one(), - "cd_nomenclature", - ) + DB.session.execute( + select(TNomenclatures.cd_nomenclature).where( + TNomenclatures.id_nomenclature == id_nomenc + ) + ).scalar_one() == "2" ): return self.__get_id_nomenc(self.__get_id_type("HIERARCHY"), "moyen") if ( - getattr( - DB.session.query(TNomenclatures) - .filter(TNomenclatures.id_nomenclature == id_nomenc) - .one(), - "cd_nomenclature", - ) + DB.session.execute( + select(TNomenclatures.cd_nomenclature).where( + TNomenclatures.id_nomenclature == id_nomenc + ) + ).scalar_one() == "3" ): return self.__get_id_nomenc(self.__get_id_type("HIERARCHY"), "mauvais") @@ -253,24 +241,23 @@ def __get_qualif_heritage(self): if not nb: nb = 0 try: - qualif = ( - DB.session.query(CorRbRules, TItems, CorItemValue) + qualif = DB.session.execute( + select(CorRbRules, TItems, CorItemValue) .join(TItems, TItems.cor_rule_id == CorRbRules.cor_rule_id) .join(CorItemValue, TItems.attribute_id == CorItemValue.attribute_id) - .filter( + .where( and_( CorRbRules.rb_id == self.rb_id, CorRbRules.rule_id == self.rule_id, ) ) - .filter( + .where( and_( CorItemValue.val_min.__le__(nb), CorItemValue.val_max.__ge__(nb), ) ) - .first() - ) + ).first() except Exception as e: exc_type, value, tb = sys.exc_info() raise ZHApiError( @@ -340,29 +327,23 @@ def __get_qualif_eco(self): if len(q_functions) >= 1: # if 61 and/or 62 : get nomenc id of continum ('res') - return getattr( - DB.session.query(TNomenclatures) - .filter( + return DB.session.execute( + select(TNomenclatures.id_nomenclature).where( and_( TNomenclatures.id_type == hier_type_id, TNomenclatures.cd_nomenclature == "res", ) ) - .one(), - "id_nomenclature", - ) + ).scalar_one() else: - return getattr( - DB.session.query(TNomenclatures) - .filter( + return DB.session.execute( + select(TNomenclatures.id_nomenclature).where( and_( TNomenclatures.id_type == hier_type_id, TNomenclatures.cd_nomenclature == "iso", ) ) - .one(), - "id_nomenclature", - ) + ).scalar_one() except ZHApiError as e: raise ZHApiError( message=str(e.message), @@ -382,17 +363,19 @@ def __get_selected_status(self): try: return [ getattr(q_.TNomenclatures, "id_nomenclature") - for q_ in DB.session.query(CorZhProtection, CorProtectionLevelType, TNomenclatures) - .join( - CorProtectionLevelType, - CorZhProtection.id_protection == CorProtectionLevelType.id_protection, - ) - .join( - TNomenclatures, - TNomenclatures.id_nomenclature == CorProtectionLevelType.id_protection_status, - ) - .filter(CorZhProtection.id_zh == self.id_zh) - .all() + for q_ in DB.session.execute( + select(CorZhProtection, CorProtectionLevelType, TNomenclatures) + .join( + CorProtectionLevelType, + CorZhProtection.id_protection == CorProtectionLevelType.id_protection, + ) + .join( + TNomenclatures, + TNomenclatures.id_nomenclature + == CorProtectionLevelType.id_protection_status, + ) + .where(CorZhProtection.id_zh == self.id_zh) + ).all() ] except ZHApiError as e: raise ZHApiError( @@ -415,16 +398,15 @@ def __get_selected_functions(self, nomenc_ids): # type_id = getattr(DB.session.query(BibNomenclaturesTypes).filter( # BibNomenclaturesTypes.mnemonique == nomenc_type_mnemo).one(), 'id_type') # get selected functions - q_ = ( - DB.session.query(TFunctions, TNomenclatures) + q_ = DB.session.execute( + select(TFunctions, TNomenclatures) .join( TNomenclatures, TNomenclatures.id_nomenclature == TFunctions.id_function, ) - .filter(TFunctions.id_zh == self.id_zh) - .filter(TNomenclatures.id_nomenclature.in_(nomenc_ids)) - .all() - ) + .where(TFunctions.id_zh == self.id_zh) + .where(TNomenclatures.id_nomenclature.in_(nomenc_ids)) + ).all() return q_ except ZHApiError as e: raise ZHApiError( @@ -444,12 +426,11 @@ def __get_selected_functions(self, nomenc_ids): def __get_id_type(self, mnemo): try: # get id_type in TNomenclatures - return getattr( - DB.session.query(BibNomenclaturesTypes) - .filter(BibNomenclaturesTypes.mnemonique == mnemo) - .one(), - "id_type", - ) + return DB.session.execute( + select(BibNomenclaturesTypes.id_type).where( + BibNomenclaturesTypes.mnemonique == mnemo + ) + ).scalar_one() except Exception as e: exc_type, value, tb = sys.exc_info() raise ZHApiError( @@ -493,11 +474,12 @@ def __get_combination(self): "mnemo": nomenc.TNomenclatures.mnemonique, "id": nomenc.TNomenclatures.id_nomenclature, } - for nomenc in DB.session.query(BibNomenclaturesTypes, TNomenclatures) - .join(BibNomenclaturesTypes) - .filter(BibNomenclaturesTypes.mnemonique == "FONCTIONS_QUALIF") - .order_by(TNomenclatures.id_nomenclature) - .all() + for nomenc in DB.session.execute( + select(BibNomenclaturesTypes, TNomenclatures) + .join(BibNomenclaturesTypes) + .where(BibNomenclaturesTypes.mnemonique == "FONCTIONS_QUALIF") + .order_by(TNomenclatures.id_nomenclature) + ).all() ] # get qualif combination of selected functions @@ -509,10 +491,9 @@ def __get_qualif_cat4_cat5(self): try: combination = self.__get_combination() # set qualif_id - qualif_id = getattr( - DB.session.query(TCorQualif).filter(TCorQualif.combination == combination).first(), - "id_qualification", - ) + qualif_id = DB.session.scalars( + select(TCorQualif.id_qualification).where(TCorQualif.combination == combination) + ).first() return qualif_id except ZHApiError as e: raise ZHApiError( @@ -531,7 +512,9 @@ def __get_qualif_cat4_cat5(self): def __get_tzh_val(self, field): try: - return getattr(DB.session.query(TZH).filter(TZH.id_zh == self.id_zh).one(), field) + return getattr( + DB.session.execute(select(TZH).where(TZH.id_zh == self.id_zh)).scalar_one(), field + ) except Exception as e: exc_type, value, tb = sys.exc_info() raise ZHApiError( @@ -584,56 +567,53 @@ def __get_qualif(self): def __get_qualif_management(self): try: cd_id_nature_naturaliste = getattr( - DB.session.query(BibNomenclaturesTypes, TNomenclatures) - .join( - TNomenclatures, - TNomenclatures.id_type == BibNomenclaturesTypes.id_type, - ) - .filter( - and_( - BibNomenclaturesTypes.mnemonique == "PLAN_GESTION", - TNomenclatures.cd_nomenclature == "5", + DB.session.execute( + select(BibNomenclaturesTypes, TNomenclatures) + .join( + TNomenclatures, + TNomenclatures.id_type == BibNomenclaturesTypes.id_type, + ) + .where( + and_( + BibNomenclaturesTypes.mnemonique == "PLAN_GESTION", + TNomenclatures.cd_nomenclature == "5", + ) ) ) - .one() + .all()[0] .TNomenclatures, "id_nomenclature", ) selected_id_nature = [ getattr(q_.TManagementPlans, "id_nature") - for q_ in DB.session.query(TManagementPlans, TManagementStructures) - .join( - TManagementStructures, - TManagementPlans.id_structure == TManagementStructures.id_structure, - ) - .filter(TManagementStructures.id_zh == self.id_zh) - .all() + for q_ in DB.session.execute( + select(TManagementPlans, TManagementStructures) + .join( + TManagementStructures, + TManagementPlans.id_structure == TManagementStructures.id_structure, + ) + .where(TManagementStructures.id_zh == self.id_zh) + ).all() ] if cd_id_nature_naturaliste in selected_id_nature: # if id_nature == 'naturaliste' in selected plans : return - return getattr( - DB.session.query(TNomenclatures) - .filter( + return DB.session.execute( + select(TNomenclatures.id_nomenclature).where( and_( TNomenclatures.id_type == self.__get_id_type("HIERARCHY"), TNomenclatures.cd_nomenclature == "OUI", ) ) - .one(), - "id_nomenclature", - ) + ).scalar_one() else: - return getattr( - DB.session.query(TNomenclatures) - .filter( + return DB.session.execute( + select(TNomenclatures.id_nomenclature).where( and_( TNomenclatures.id_type == self.__get_id_type("HIERARCHY"), TNomenclatures.cd_nomenclature == "NON", ) ) - .one(), - "id_nomenclature", - ) + ).scalar_one() except ZHApiError as e: raise ZHApiError( message=str(e.message), @@ -654,16 +634,17 @@ def __get_knowledge(self): if self.active: if self.abb == "hab": is_carto = ( - DB.session.query(TZH).filter(TZH.id_zh == self.id_zh).one().is_carto_hab + DB.session.execute(select(TZH).where(TZH.id_zh == self.id_zh)) + .scalar_one() + .is_carto_hab ) if is_carto: return 3 return 2 elif self.abb in ["flore", "vertebrates", "invertebrates"]: is_other_inventory = ( - DB.session.query(TZH) - .filter(TZH.id_zh == self.id_zh) - .one() + DB.session.execute(select(TZH).where(TZH.id_zh == self.id_zh)) + .scalar_one() .is_other_inventory ) is_id_nature_plan_2 = self.__get_id_plan() @@ -676,22 +657,27 @@ def __get_knowledge(self): try: # return id_knowledge if abb function selected knowledge_id = ( - DB.session.query(TFunctions.id_knowledge) - .filter( - and_( - TFunctions.id_zh == self.id_zh, - TFunctions.id_qualification == self.qualif_id, + DB.session.execute( + select(TFunctions.id_knowledge) + .where( + and_( + TFunctions.id_zh == self.id_zh, + TFunctions.id_qualification == self.qualif_id, + ) ) + .where(TFunctions.id_function == CorRuleNomenc.nomenc_id) + .where(CorRuleNomenc.rule_id == self.rule_id) ) - .filter(TFunctions.id_function == CorRuleNomenc.nomenc_id) - .filter(CorRuleNomenc.rule_id == self.rule_id) - .one() + .scalar_one() .id_knowledge ) return ( - DB.session.query(BibNoteTypes) - .filter(BibNoteTypes.id_knowledge == knowledge_id) - .one() + DB.session.execute( + select(BibNoteTypes).where( + BibNoteTypes.id_knowledge == knowledge_id + ) + ) + .scalar_one() .note_id ) except: @@ -755,8 +741,8 @@ def __set_protection_knowledge(self): DB.session.close() def __get_id_plan(self): - q_plans = ( - DB.session.query(TManagementStructures, TManagementPlans) + q_plans = DB.session.execute( + select(TManagementStructures, TManagementPlans) .join( TManagementPlans, TManagementStructures.id_structure == TManagementPlans.id_structure, @@ -765,14 +751,13 @@ def __get_id_plan(self): TNomenclatures, TNomenclatures.id_nomenclature == TManagementPlans.id_nature, ) - .filter( + .where( and_( TManagementStructures.id_zh == self.id_zh, TNomenclatures.mnemonique == "Naturaliste", ) ) - .all() - ) + ).all() if q_plans: return True return False @@ -782,17 +767,20 @@ def __check_qualif(self, qualif_id): if self.active: attribute_id_list = [ getattr(item, "attribute_id") - for item in DB.session.query(TItems) - .filter(TItems.cor_rule_id == self.cor_rule_id) - .all() + for item in DB.session.scalars( + select(TItems).where(TItems.cor_rule_id == self.cor_rule_id) + ).all() ] if qualif_id not in attribute_id_list: raise ZHApiError( message="wrong_qualif", details="zh qualif ({}) provided for {} rule is not part of the qualif list defined in the river basin hierarchy rules".format( - DB.session.query(TNomenclatures) - .filter(TNomenclatures.id_nomenclature == qualif_id) - .one() + DB.session.execute( + select(TNomenclatures).where( + TNomenclatures.id_nomenclature == qualif_id + ) + ) + .scalar_one() .mnemonique, self.abb, ), @@ -817,17 +805,15 @@ def __check_qualif(self, qualif_id): def __set_note(self): try: if self.active: - result = ( - DB.session.query(TItems) - .filter( + result = DB.session.execute( + select(TItems).where( and_( TItems.attribute_id == self.qualif_id, TItems.cor_rule_id == self.cor_rule_id, TItems.note_type_id == self.knowledge, ) ) - .one() - ) + ).scalar_one() note = round(result.note, 2) attribute_id = result.attribute_id note_type_id = result.note_type_id @@ -858,9 +844,9 @@ def __get_denominator(self): if self.active: return max( getattr(val, "note") - for val in DB.session.query(TItems) - .filter(TItems.cor_rule_id == self.cor_rule_id) - .all() + for val in DB.session.scalars( + select(TItems).where(TItems.cor_rule_id == self.cor_rule_id) + ).all() ) except Exception as e: exc_type, value, tb = sys.exc_info() @@ -872,19 +858,21 @@ def __get_denominator(self): def __get_rule_name(self): try: return ( - DB.session.query(TRules, BibHierSubcategories) - .join(TRules) - .filter(TRules.rule_id == self.rule_id) - .one() - .BibHierSubcategories.label.capitalize() + DB.session.execute( + select(TRules, BibHierCategories) + .join(TRules) + .where(TRules.rule_id == self.rule_id) + ) + .all()[0] + .BibHierCategories.label.capitalize() ) except NoResultFound: pass return ( - DB.session.query(TRules, BibHierCategories) - .join(TRules) - .filter(TRules.rule_id == self.rule_id) - .one() + DB.session.execute( + select(TRules, BibHierCategories).join(TRules).where(TRules.rule_id == self.rule_id) + ) + .all()[0] .BibHierCategories.label.capitalize() ) @@ -894,17 +882,14 @@ def __get_knowledge_mnemo(self): if self.knowledge == 1: return None else: - return getattr( - DB.session.query(TNomenclatures, BibNoteTypes) + return DB.session.execute( + select(TNomenclatures.mnemonique, BibNoteTypes) .join( BibNoteTypes, TNomenclatures.id_nomenclature == BibNoteTypes.id_knowledge, ) - .filter(BibNoteTypes.note_id == self.knowledge) - .one() - .TNomenclatures, - "mnemonique", - ) + .where(BibNoteTypes.note_id == self.knowledge) + ).scalar_one() except Exception as e: exc_type, value, tb = sys.exc_info() raise ZHApiError( @@ -915,12 +900,11 @@ def __get_knowledge_mnemo(self): def __get_qualif_mnemo(self): try: if self.active: - return getattr( - DB.session.query(TNomenclatures) - .filter(TNomenclatures.id_nomenclature == self.qualif_id) - .one(), - "label_default", - ) + return DB.session.execute( + select(TNomenclatures.label_default).where( + TNomenclatures.id_nomenclature == self.qualif_id + ) + ).scalar_one() except Exception as e: exc_type, value, tb = sys.exc_info() raise ZHApiError( @@ -960,12 +944,9 @@ def denominator(self, value): self.__denominator = Hierarchy.get_denom(self.rb_id, value) def __get_name(self): - return getattr( - DB.session.query(BibHierCategories) - .filter(BibHierCategories.abbreviation == self.abb) - .one(), - "label", - ) + return DB.session.execute( + select(BibHierCategories.label).where(BibHierCategories.abbreviation == self.abb) + ).scalar_one() @staticmethod def get_note(value): @@ -1187,17 +1168,15 @@ def __get_rb(self): return None if len(q_rb) > 1: return get_main_rb(q_rb) - return ( - DB.session.query(CorZhRb, TRiverBasin) - .join(TRiverBasin) - .filter(CorZhRb.id_zh == self.id_zh) - .one() - .TRiverBasin.id_rb - ) + return DB.session.execute( + select(CorZhRb.id_rb, TRiverBasin).join(TRiverBasin).where(CorZhRb.id_zh == self.id_zh) + ).scalar_one() def __check_if_rules(self): try: - if not DB.session.query(CorRbRules).filter(CorRbRules.rb_id == self.rb_id).first(): + if not DB.session.scalars( + select(CorRbRules).where(CorRbRules.rb_id == self.rb_id) + ).first(): raise ZHApiError( message="no_rb_rules", details="no existing rules for the river basin", @@ -1215,9 +1194,13 @@ def __check_if_rules(self): @staticmethod def get_denom(rb_id, col_name): - rb_name = DB.session.query(TRiverBasin).filter(TRiverBasin.id_rb == rb_id).one().name + rb_name = DB.session.execute( + select(TRiverBasin.name).where(TRiverBasin.id_rb == rb_id) + ).scalar_one() return getattr( - DB.session.query(RbNotesSummary).filter(RbNotesSummary.bassin_versant == rb_name).one(), + DB.session.execute( + select(RbNotesSummary).where(RbNotesSummary.bassin_versant == rb_name) + ).scalar_one(), col_name, ) @@ -1236,10 +1219,9 @@ def get_str_note(note, denominator): def as_dict(self): return { - "river_basin_name": DB.session.query(TRiverBasin) - .filter(TRiverBasin.id_rb == self.rb_id) - .one() - .name, + "river_basin_name": DB.session.execute( + select(TRiverBasin.name).where(TRiverBasin.id_rb == self.rb_id) + ).scalar_one(), "volet1": self.volet1.__str__(), "volet2": self.volet2.__str__(), "global_note": Hierarchy.get_str_note(self.global_note, self.total_denom), @@ -1253,7 +1235,7 @@ def get_all_hierarchy_fields(id_rb: int): tableName="all_rb_rules", schemaName="pr_zh", filters={"id_rb": id_rb, "orderby": "name"}, - limit=-1, + limit=100000, ) results = query.return_query() diff --git a/backend/gn_module_zh/model/cards.py b/backend/gn_module_zh/model/cards.py index 90ffc3ce..795b5e19 100644 --- a/backend/gn_module_zh/model/cards.py +++ b/backend/gn_module_zh/model/cards.py @@ -3,6 +3,7 @@ from ref_geo.models import BibAreasTypes, LAreas from geonature.utils.env import DB +from sqlalchemy.sql import select from pypn_habref_api.models import Habref from pypnnomenclature.models import TNomenclatures @@ -31,17 +32,15 @@ class Utils(ZH): def get_mnemo(ids): if ids: if type(ids) is int: - return ( - DB.session.query(TNomenclatures) - .filter(TNomenclatures.id_nomenclature == ids) - .one() - .label_default + return DB.session.scalar( + select(TNomenclatures.label_default).where( + TNomenclatures.id_nomenclature == ids + ) ) return [ - DB.session.query(TNomenclatures) - .filter(TNomenclatures.id_nomenclature == id) - .one() - .label_default + DB.session.scalar( + select(TNomenclatures.label_default).where(TNomenclatures.id_nomenclature == id) + ) for id in ids ] return [] @@ -50,18 +49,16 @@ def get_mnemo(ids): def get_cd_and_mnemo(ids): if ids: if type(ids) is int: - result = ( - DB.session.query(TNomenclatures) - .filter(TNomenclatures.id_nomenclature == ids) - .one() - ) + result = DB.session.execute( + select(TNomenclatures).where(TNomenclatures.id_nomenclature == ids) + ).scalar_one() return (result.cd_nomenclature, result.label_default) - return ( - DB.session.query(TNomenclatures.cd_nomenclature, TNomenclatures.label_default) - .filter(TNomenclatures.id_nomenclature.in_(ids)) - .all() - ) + return DB.session.execute( + select(TNomenclatures.cd_nomenclature, TNomenclatures.label_default).where( + TNomenclatures.id_nomenclature.in_(ids) + ) + ).all() return [] @@ -380,23 +377,19 @@ def __init__(self, id_corine_bio, id_cahier_hab, id_preservation_state, hab_cove self.hab_cover: int = hab_cover def __str__(self): - hab_biotope = ( - DB.session.query(Habref) - .filter(Habref.lb_code == self.id_corine_bio) - .filter(Habref.cd_typo == 22) - .one() - ) + hab_biotope = DB.session.execute( + select(Habref).where(Habref.lb_code == self.id_corine_bio).where(Habref.cd_typo == 22) + ).scalar_one() biotope_lb_hab_fr = hab_biotope.lb_hab_fr biotope_lb_code = hab_biotope.lb_code - cahier = DB.session.query(Habref).filter(Habref.cd_hab == self.id_cahier_hab).one() + cahier = DB.session.execute( + select(Habref).where(Habref.cd_hab == self.id_cahier_hab) + ).scalar_one() cahier_lb_hab_fr = cahier.lb_hab_fr cahier_lb_code = cahier.lb_code - priority = ( - DB.session.query(CorChStatus) - .filter(CorChStatus.lb_code == cahier_lb_code) - .one() - .priority - ) + priority = DB.session.execute( + select(CorChStatus.priority).where(CorChStatus.lb_code == cahier_lb_code).distinct() + ).scalar_one() return { "biotope": biotope_lb_code + " - " + biotope_lb_hab_fr, "etat": Utils.get_mnemo(self.id_preservation_state), @@ -502,22 +495,25 @@ def __str__(self): "hydros": self.hydro_zones, } + # TODO: replace in "where with multiples conditions" the coma by AND def __get_river_basins(self): return [ name - for (name,) in DB.session.query(TRiverBasin.name) - .filter(TRiverBasin.id_rb == CorZhRb.id_rb) - .filter(CorZhRb.id_zh == self.id_zh) - .all() + for name in DB.session.execute( + select(TRiverBasin.name).where( + TRiverBasin.id_rb == CorZhRb.id_rb, CorZhRb.id_zh == self.id_zh + ) + ).all() ] def __get_hydro_zones(self): return [ name - for (name,) in DB.session.query(THydroArea.name) - .filter(THydroArea.id_hydro == CorZhHydro.id_hydro) - .filter(CorZhHydro.id_zh == self.id_zh) - .distinct() + for name in DB.session.execute( + select(THydroArea.name) + .where(THydroArea.id_hydro == CorZhHydro.id_hydro, CorZhHydro.id_zh == self.id_zh) + .distinct() + ).all() ] @@ -674,19 +670,14 @@ def instruments(self, instruments): def other_ref_geo(self, ref_geo): id_types = CorZhArea.get_id_types_ref_geo(self.id_zh, ref_geo) refs = [] - for ref in CorZhArea.get_ref_geo_info(self.id_zh, id_types): - for i in ref: - type_code = ( - DB.session.query(BibAreasTypes) - .filter(BibAreasTypes.id_type == i.LAreas.id_type) - .one() - .type_code - ) + for ref_infos in CorZhArea.get_ref_geo_info(self.id_zh, id_types): + for info in ref_infos: + type_code = DB.session.get(BibAreasTypes, info.LAreas.id_type) refs.append( { - "area_name": i.LAreas.area_name, - "area_code": i.LAreas.area_code, - "url": i.LAreas.source, + "area_name": info.LAreas.area_name, + "area_code": info.LAreas.area_code, + "url": info.LAreas.source, "type_code": type_code, "zh_type_name": [ ref["zh_name"] @@ -722,11 +713,11 @@ def protections(self, protections): self.__protections: list(int) = protections def __str_protections(self): - q_protections = ( - DB.session.query(CorProtectionLevelType) - .filter(CorProtectionLevelType.id_protection_status.in_(self.protections)) - .all() - ) + q_protections = DB.session.scalars( + select(CorProtectionLevelType).where( + CorProtectionLevelType.id_protection_status.in_(self.protections) + ) + ).all() temp = [ { "status": Utils.get_mnemo(protection.id_protection_status), @@ -777,10 +768,9 @@ def set_management(self, id_org, plans): def __str__(self): return { - "structure": DB.session.query(BibOrganismes) - .filter(BibOrganismes.id_org == self.id_org) - .one() - .name, + "structure": DB.session.scalar( + select(BibOrganismes.name).where(BibOrganismes.id_org == self.id_org) + ), "plans": [plan.__str__() for plan in self.plans], } @@ -819,17 +809,15 @@ def __init__(self, id_area, id_doc_type, id_cors, remark): def __str__(self): return { - "commune": DB.session.query(LAreas) - .filter(LAreas.id_area == self.id_area) - .one() - .area_name, + "commune": DB.session.get(LAreas, self.id_area), "type_doc": Utils.get_mnemo(self.id_doc_type), "type_classement": [ Utils.get_mnemo( - DB.session.query(CorUrbanTypeRange) - .filter(CorUrbanTypeRange.id_cor == id) - .one() - .id_range_type + DB.session.scalar( + select(CorUrbanTypeRange.id_range_type).where( + CorUrbanTypeRange.id_cor == id + ) + ) ) for id in self.id_cors ], @@ -1009,10 +997,7 @@ def __init__(self, id_action, id_priority_level, remark): def __str__(self): return { - "proposition": DB.session.query(BibActions) - .filter(BibActions.id_action == self.id_action) - .one() - .name, + "proposition": DB.session.get(BibActions, self.id_action).name, "niveau": Utils.get_mnemo(self.id_priority_level), "remarque": Utils.get_string(self.remark), } diff --git a/backend/gn_module_zh/model/code.py b/backend/gn_module_zh/model/code.py index 132fcd57..6cea6918 100644 --- a/backend/gn_module_zh/model/code.py +++ b/backend/gn_module_zh/model/code.py @@ -1,7 +1,7 @@ import sys from geonature.utils.env import DB -from sqlalchemy.sql import func +from sqlalchemy.sql import func, select from ..api_error import ZHApiError from .zh import ZH @@ -18,15 +18,18 @@ def get_departments(self): try: departments = CorZhArea.get_departments(self.id_zh) area = 0 - my_geom = ( - DB.session.query(func.ST_Transform(func.ST_SetSRID(TZH.geom, 4326), 2154)) - .filter(TZH.id_zh == self.id_zh) - .one()[0] - ) + my_geom = DB.session.execute( + select(func.ST_Transform(func.ST_SetSRID(TZH.geom, 4326), 2154)).where( + TZH.id_zh == self.id_zh + ) + ).scalar_one() main_dep = None for dep in departments: - if DB.session.scalar(dep.LAreas.geom.ST_Intersection(my_geom).ST_Area()) > area: - area = DB.session.scalar(dep.LAreas.geom.ST_Intersection(my_geom).ST_Area()) + dep_area = DB.session.scalar( + select(dep.LAreas.geom.ST_Intersection(my_geom).ST_Area()) + ) + if dep_area > area: + area = dep_area main_dep = dep.LAreas.area_code if main_dep is None: raise ZHApiError(message="no_department", details="main_dep value is none") @@ -44,7 +47,7 @@ def get_organism(self): def get_number(self): base_code = self.get_departments() + self.get_organism() - q_codes = DB.session.query(TZH).filter(TZH.code.contains(base_code)).all() + q_codes = DB.session.scalars(select(TZH).where(TZH.code.contains(base_code))).all() if q_codes: code_numbers = [int(zh.code.split(self.get_organism())[1]) for zh in q_codes] max_code = max(code_numbers) diff --git a/backend/gn_module_zh/model/repositories.py b/backend/gn_module_zh/model/repositories.py index f2100867..20b3a679 100644 --- a/backend/gn_module_zh/model/repositories.py +++ b/backend/gn_module_zh/model/repositories.py @@ -1,5 +1,6 @@ from geonature.utils.env import DB from werkzeug.exceptions import NotFound +from sqlalchemy.sql import select class ZhRepository: @@ -17,7 +18,7 @@ def delete(self, id_zh, user, user_cruved): - id_zh: integer - info_user: TRole object model""" level = user_cruved["D"] - zh = DB.session.query(self.model).get(id_zh) + zh = DB.session.get(self.model, id_zh) if zh: zh = zh.get_zh_if_allowed(user, "D", level) DB.session.delete(zh) diff --git a/backend/gn_module_zh/model/zh.py b/backend/gn_module_zh/model/zh.py index 404759a3..84c4a945 100644 --- a/backend/gn_module_zh/model/zh.py +++ b/backend/gn_module_zh/model/zh.py @@ -1,5 +1,6 @@ # instance de la BDD from geonature.utils.env import DB +from sqlalchemy.sql import select from .zh_schema import ( TZH, @@ -32,11 +33,11 @@ class ZH(TZH): __abstract__ = True def __init__(self, id_zh): - self.zh = DB.session.query(TZH).filter(TZH.id_zh == id_zh).one() + self.zh = DB.session.get(TZH, id_zh) @staticmethod def get_data_by_id(table_name, id_zh): - return DB.session.query(table_name).filter(table_name.id_zh == id_zh).all() + return DB.session.scalars(select(table_name).where(table_name.id_zh == id_zh)).all() def get_id_lims(self): lim_list = CorLimList.get_lims_by_id(self.zh.id_lim_list) @@ -141,11 +142,11 @@ def get_managements(self): q_management_structures = ZH.get_data_by_id(TManagementStructures, self.zh.id_zh) managements = [] for management in q_management_structures: - q_management_plans = ( - DB.session.query(TManagementPlans) - .filter(TManagementPlans.id_structure == management.id_structure) - .all() - ) + q_management_plans = DB.session.scalars( + select(TManagementPlans).where( + TManagementPlans.id_structure == management.id_structure + ) + ).all() plans = [] if q_management_plans: for plan in q_management_plans: @@ -178,10 +179,11 @@ def get_instruments(self): def get_protections(self): return { "protections": [ - DB.session.query(CorProtectionLevelType) - .filter(CorProtectionLevelType.id_protection == protec) - .one() - .id_protection_status + DB.session.execute( + select(CorProtectionLevelType.id_protection_status).where( + CorProtectionLevelType.id_protection == protec + ) + ).scalar_one() for protec in [ protection.id_protection for protection in ZH.get_data_by_id(CorZhProtection, self.zh.id_zh) @@ -197,9 +199,9 @@ def get_urban_docs(self): "id_doc_type": urban_doc.id_doc_type, "id_cors": [ doc.id_cor - for doc in DB.session.query(CorZhDocRange) - .filter(CorZhDocRange.id_doc == urban_doc.id_doc) - .all() + for doc in DB.session.scalars( + select(CorZhDocRange).where(CorZhDocRange.id_doc == urban_doc.id_doc) + ).all() ], "remark": urban_doc.remark, } @@ -252,9 +254,9 @@ def get_regions(self, query): for municipality in query: if municipality.LiMunicipalities.insee_reg not in region_list: region_list.append(municipality.LiMunicipalities.insee_reg) - q_region = ( - DB.session.query(InseeRegions).filter(InseeRegions.insee_reg.in_(region_list)).all() - ) + q_region = DB.session.scalars( + select(InseeRegions).where(InseeRegions.insee_reg.in_(region_list)) + ).all() regions = [region.region_name for region in q_region] return regions diff --git a/backend/gn_module_zh/model/zh_schema.py b/backend/gn_module_zh/model/zh_schema.py index e8e2ba19..8953de87 100644 --- a/backend/gn_module_zh/model/zh_schema.py +++ b/backend/gn_module_zh/model/zh_schema.py @@ -91,12 +91,13 @@ class Nomenclatures(TNomenclatures): @staticmethod def get_nomenclature_info(bib_mnemo): - q = TNomenclatures.query.filter_by( - id_type=select([func.ref_nomenclatures.get_id_nomenclature_type(bib_mnemo)]) + # todo + q = select(TNomenclatures).where( + TNomenclatures.id_type == (func.ref_nomenclatures.get_id_nomenclature_type(bib_mnemo)) ) if bib_mnemo == "SDAGE": q = q.order_by(TNomenclatures.id_nomenclature) - return q.all() + return DB.session.scalars(q).all() @serializable @@ -127,7 +128,8 @@ class BibSiteSpace(DB.Model): @staticmethod def get_bib_site_spaces(): - bib_site_spaces = DB.session.query(BibSiteSpace).all() + # bib_site_spaces = DB.session.execute(select(BibSiteSpace)).scalars().all() + bib_site_spaces = DB.session.scalars(select(BibSiteSpace)).all() bib_site_spaces_list = [bib_site_space.as_dict() for bib_site_space in bib_site_spaces] return bib_site_spaces_list @@ -143,12 +145,15 @@ class BibOrganismes(DB.Model): @staticmethod def get_abbrevation(id_org): - org = DB.session.query(BibOrganismes).filter(BibOrganismes.id_org == id_org).one() + org = DB.session.execute( + select(BibOrganismes).where(BibOrganismes.id_org == id_org) + ).scalar_one() return org.abbrevation @staticmethod def get_bib_organisms(org_type): - bib_organismes = DB.session.query(BibOrganismes).all() + # bib_organismes = DB.session.execute(select(BibOrganismes)).scalars().all() + bib_organismes = DB.session.scalars(select(BibOrganismes)).all() if org_type == "operator": return [bib_org.as_dict() for bib_org in bib_organismes if bib_org.is_op_org] elif org_type == "management_structure": @@ -165,7 +170,7 @@ class CorLimList(DB.Model): id_lim = DB.Column(DB.Integer, ForeignKey(TNomenclatures.id_nomenclature), primary_key=True) def get_lims_by_id(id): - return DB.session.query(CorLimList).filter(CorLimList.id_lim_list == id).all() + return DB.session.scalars(select(CorLimList).where(CorLimList.id_lim_list == id)).all() @serializable @@ -262,53 +267,50 @@ def get_geofeature(self, recursif=True, relationships=()): @staticmethod def get_site_space_name(id): - return DB.session.query(BibSiteSpace).filter(BibSiteSpace.id_site_space == id).one().name + return DB.session.scalar(select(BibSiteSpace.name).where(BibSiteSpace.id_site_space == id)) @staticmethod def get_tzh_by_id(id): - return DB.session.query(TZH).filter(TZH.id_zh == id).one() + return DB.session.scalar(select(TZH).where(TZH.id_zh == id)) @staticmethod def get_zh_area_intersected(zh_area_type, id_zh_geom): if zh_area_type == "river_basin": - q = ( - DB.session.query(TRiverBasin) - .filter(TRiverBasin.geom.ST_Intersects(cast(id_zh_geom, Geography))) - .all() - ) + q = DB.session.scalars( + select(TRiverBasin).where( + TRiverBasin.geom.ST_Intersects(cast(id_zh_geom, Geography)) + ) + ).all() if zh_area_type == "hydro_area": - q = ( - DB.session.query(THydroArea) - .filter(THydroArea.geom.ST_Intersects(cast(id_zh_geom, Geography))) - .all() - ) + q = DB.session.scalars( + select(THydroArea).where(THydroArea.geom.ST_Intersects(cast(id_zh_geom, Geography))) + ).all() if zh_area_type == "fct_area": - q = ( - DB.session.query(TFctArea) - .filter(TFctArea.geom.ST_Intersects(cast(id_zh_geom, Geography))) - .all() - ) + q = DB.session.scalars( + select(TFctArea).where(TFctArea.geom.ST_Intersects(cast(id_zh_geom, Geography))) + ).all() return q @hybrid_property def delims(self): - delims = [ - element.TNomenclatures.mnemonique - for element in DB.session.query(CorLimList, TNomenclatures) - .filter(CorLimList.id_lim_list == self.id_lim_list) - .filter(TNomenclatures.id_nomenclature == CorLimList.id_lim) - .all() - ] + query = select(CorLimList, TNomenclatures).where( + and_( + TNomenclatures.id_nomenclature == CorLimList.id_lim, + CorLimList.id_lim_list == self.id_lim_list, + ) + ) + delims = [element.TNomenclatures.mnemonique for element in DB.session.execute(query).all()] return ", ".join([str(item) for item in delims]) @hybrid_property def bassin_versant(self): bassin_versant = [ name - for (name,) in DB.session.query(TRiverBasin.name) - .filter(TRiverBasin.id_rb == CorZhRb.id_rb) - .filter(CorZhRb.id_zh == self.id_zh) - .all() + for name in DB.session.execute( + select(TRiverBasin.name).where( + TRiverBasin.id_rb == CorZhRb.id_rb, CorZhRb.id_zh == self.id_zh + ) + ).all() ] return ", ".join([str(item) for item in bassin_versant]) @@ -324,31 +326,32 @@ class CorZhArea(DB.Model): @staticmethod def get_id_type(mnemo): return ( - DB.session.query(BibAreasTypes).filter(BibAreasTypes.type_name == mnemo).one().id_type + DB.session.scalars(select(BibAreasTypes).where(BibAreasTypes.type_name == mnemo)) + .one() + .id_type ) @staticmethod def get_departments(id_zh): - return ( - DB.session.query(CorZhArea, LAreas, TZH) + query = ( + select(CorZhArea, LAreas, TZH) .join(LAreas) - .filter( + .where( CorZhArea.id_zh == id_zh, LAreas.id_type == CorZhArea.get_id_type("Départements"), TZH.id_zh == id_zh, ) - .all() ) + return DB.session.execute(query).all() @staticmethod def get_municipalities_info(id_zh): - return ( - DB.session.query(CorZhArea, LiMunicipalities, TZH) + return DB.session.execute( + select(CorZhArea, LiMunicipalities, TZH) .join(LiMunicipalities, LiMunicipalities.id_area == CorZhArea.id_area) - .filter(CorZhArea.id_zh == id_zh, TZH.id_zh == id_zh) + .where(CorZhArea.id_zh == id_zh, TZH.id_zh == id_zh) .order_by(LiMunicipalities.nom_com) - .all() - ) + ).all() @staticmethod def get_id_types_ref_geo(id_zh, ref_geo_config): @@ -356,20 +359,22 @@ def get_id_types_ref_geo(id_zh, ref_geo_config): for ref in ref_geo_config: if ref["active"]: ids.append( - DB.session.query(BibAreasTypes) - .filter(BibAreasTypes.type_code == ref["type_code_ref_geo"]) - .one() - .id_type + DB.session.scalar( + select(BibAreasTypes.id_type).where( + BibAreasTypes.type_code == ref["type_code_ref_geo"] + ) + ) ) return ids @staticmethod def get_ref_geo_info(id_zh, id_types): return [ - DB.session.query(CorZhArea, LAreas, TZH) - .join(LAreas) - .filter(CorZhArea.id_zh == id_zh, LAreas.id_type == id_type, TZH.id_zh == id_zh) - .all() + DB.session.execute( + select(CorZhArea, LAreas, TZH) + .join(LAreas) + .where(CorZhArea.id_zh == id_zh, LAreas.id_type == id_type, TZH.id_zh == id_zh) + ).all() for id_type in id_types ] @@ -441,13 +446,12 @@ class CorZhRef(DB.Model): @staticmethod def get_references_by_id(id_zh): - return ( - DB.session.query(TReferences) + return DB.session.scalars( + select(TReferences) .join(CorZhRef) - .filter(CorZhRef.id_zh == id_zh) + .where(CorZhRef.id_zh == id_zh) .order_by(TReferences.pub_year.desc()) - .all() - ) + ).all() class CorZhLimFs(DB.Model): @@ -465,17 +469,16 @@ class CorSdageSage(DB.Model): @staticmethod def get_id_sdage_list(): - q_id_sdages = DB.session.query(func.distinct(CorSdageSage.id_sdage)).all() + q_id_sdages = DB.session.execute(select(func.distinct(CorSdageSage.id_sdage))).all() return [id[0] for id in q_id_sdages] @staticmethod def get_sage_by_id(id): - return ( - DB.session.query(CorSdageSage, TNomenclatures) + return DB.session.execute( + select(CorSdageSage, TNomenclatures) .join(TNomenclatures, TNomenclatures.id_nomenclature == CorSdageSage.id_sage) - .filter(CorSdageSage.id_sdage == id) - .all() - ) + .where(CorSdageSage.id_sdage == id) + ).all() class BibCb(DB.Model): @@ -487,17 +490,19 @@ class BibCb(DB.Model): @staticmethod def get_label(): - return ( - DB.session.query(BibCb, Habref) + return DB.session.execute( + select(BibCb, Habref) .join(Habref, BibCb.lb_code == Habref.lb_code) - .filter(Habref.cd_typo == 22) + .where(Habref.cd_typo == 22) .order_by(BibCb.lb_code) - .all() - ) + ).all() @staticmethod def get_ch(lb_code): # get cd_hab_sortie from lb_code of selected Corine Biotope + # !!! est-ce que method utilisée qqpart ? + # todo + """ cd_hab_sortie = ( DB.session.query(Habref) .filter(and_(Habref.lb_code == lb_code, Habref.cd_typo == 22)) @@ -505,11 +510,13 @@ def get_ch(lb_code): .cd_hab ) # get all cd_hab_entre corresponding to cd_hab_sortie + #todo q_cd_hab_entre = ( DB.session.query(CorespHab).filter(CorespHab.cd_hab_sortie == cd_hab_sortie).all() ) # get list of cd_hab_entre/lb_code/lb_hab_fr for each cahier habitat ch = [] + #todo for q in q_cd_hab_entre: ch.append( { @@ -525,6 +532,7 @@ def get_ch(lb_code): } ) return ch + """ class CorChStatus(DB.Model): @@ -544,15 +552,14 @@ class CorImpactTypes(DB.Model): @staticmethod def get_impacts(): - return ( - DB.session.query(CorImpactTypes, TNomenclatures) + return DB.session.execute( + select(CorImpactTypes, TNomenclatures) .join( TNomenclatures, TNomenclatures.id_nomenclature == CorImpactTypes.id_impact, ) - .filter(CorImpactTypes.active) - .all() - ) + .where(CorImpactTypes.active) + ).all() # and_(CorImpactTypes.id_impact_type == id_type, CorImpactTypes.active)).all() # def get_impact_type_list(): @@ -586,44 +593,42 @@ class CorMainFct(DB.Model): @staticmethod def get_functions(nomenc_ids): - return ( - DB.session.query(CorMainFct, TNomenclatures) + return DB.session.execute( + select(CorMainFct, TNomenclatures) .join(TNomenclatures, TNomenclatures.id_nomenclature == CorMainFct.id_function) - .filter(CorMainFct.active) - .filter(CorMainFct.id_function.in_(nomenc_ids)) - .all() - ) + .where(CorMainFct.active, CorMainFct.id_function.in_(nomenc_ids)) + ).all() @staticmethod def get_all_functions(nomenc_ids): - return ( - DB.session.query(CorMainFct, TNomenclatures) + query = ( + select(CorMainFct, TNomenclatures) .join(TNomenclatures, TNomenclatures.id_nomenclature == CorMainFct.id_function) - .filter(CorMainFct.id_function.in_(nomenc_ids)) - .all() + .where(CorMainFct.id_function.in_(nomenc_ids)) ) + return DB.session.execute(query).all() @staticmethod def get_main_function_list(ids): - q_id_types = DB.session.query(func.distinct(CorMainFct.id_main_function)).all() + # méthode utilisée ? + q_id_types = DB.session.scalars(select(func.distinct(CorMainFct.id_main_function))).all() return [id[0] for id in q_id_types if id[0] in ids] @staticmethod def get_function_by_main_function(id_main): - return ( - DB.session.query(CorMainFct, TNomenclatures) + # TODO: méthode utilisée ? + return DB.session.execute( + select(CorMainFct, TNomenclatures) .join(TNomenclatures, TNomenclatures.id_nomenclature == CorMainFct.id_function) - .filter(and_(CorMainFct.id_main_function == id_main, CorMainFct.active)) - .all() - ) + .where(and_(CorMainFct.id_main_function == id_main, CorMainFct.active)) + ).all() @staticmethod def get_mnemo_type(id_type): + # TODO: methode utilisée ? if id_type: - return ( - DB.session.query(TNomenclatures) - .filter(TNomenclatures.id_nomenclature == id_type) - .one() + return DB.session.scalar( + select(TNomenclatures).where(TNomenclatures.id_nomenclature == id_type) ) else: return "" @@ -657,11 +662,9 @@ class CorImpactList(DB.Model): @staticmethod def get_impacts_by_uuid(uuid_activity): - return ( - DB.session.query(CorImpactList) - .filter(CorImpactList.id_impact_list == uuid_activity) - .all() - ) + return DB.session.scalars( + select(CorImpactList).where(CorImpactList.id_impact_list == uuid_activity) + ).all() class TActivity(DB.Model): @@ -741,13 +744,13 @@ def get_functions_by_id_and_category(id_zh, category, is_eval=False): for nomenclature in Nomenclatures.get_nomenclature_info("FONCTIONS_QUALIF") ] - return ( - DB.session.query(TFunctions) - .filter(TFunctions.id_zh == id_zh) - .filter(TFunctions.id_function.in_(function_ids)) - .filter(TFunctions.id_qualification.in_(qualif_ids)) - .all() - ) + return DB.session.scalars( + select(TFunctions).where( + TFunctions.id_zh == id_zh, + TFunctions.id_function.in_(function_ids), + TFunctions.id_qualification.in_(qualif_ids), + ) + ).all() class THabHeritage(DB.Model): @@ -773,21 +776,20 @@ class CorUrbanTypeRange(DB.Model): @staticmethod def get_range_by_doc(doc_id): - q_ranges = ( - DB.session.query(CorUrbanTypeRange) - .filter(CorUrbanTypeRange.id_doc_type == doc_id) - .all() - ) + q_ranges = DB.session.scalars( + select(CorUrbanTypeRange).where(CorUrbanTypeRange.id_doc_type == doc_id) + ).all() ranges = [] for range in q_ranges: ranges.append( { "id_cor": range.id_cor, "id_nomenclature": range.id_range_type, - "mnemonique": DB.session.query(TNomenclatures) - .filter(TNomenclatures.id_nomenclature == range.id_range_type) - .one() - .mnemonique, + "mnemonique": DB.session.scalar( + select(TNomenclatures.mnemonique).where( + TNomenclatures.id_nomenclature == range.id_range_type + ) + ), } ) return ranges @@ -834,7 +836,7 @@ class BibActions(DB.Model): @staticmethod def get_bib_actions(): - q_bib_actions = DB.session.query(BibActions).all() + q_bib_actions = DB.session.scalars(select(BibActions)).all() bib_actions_list = [bib_action.as_dict() for bib_action in q_bib_actions] return bib_actions_list diff --git a/backend/gn_module_zh/nomenclatures.py b/backend/gn_module_zh/nomenclatures.py index ad6f28cd..38f0491a 100644 --- a/backend/gn_module_zh/nomenclatures.py +++ b/backend/gn_module_zh/nomenclatures.py @@ -4,6 +4,7 @@ from pypn_habref_api.models import CorespHab, Habref, TypoRef from pypnnomenclature.models import BibNomenclaturesTypes, TNomenclatures from sqlalchemy import and_ +from sqlalchemy.sql import select from .api_error import ZHApiError from .model.zh_schema import ( @@ -61,42 +62,35 @@ def get_corine_biotope(): def get_ch(lb_code): try: - CH_typo = DB.session.query(TypoRef).filter(TypoRef.cd_table == "TYPO_CH").one().cd_typo - CB_typo = ( - DB.session.query(TypoRef) - .filter(TypoRef.cd_table == "TYPO_CORINE_BIOTOPES") - .one() - .cd_typo + CH_typo = DB.session.scalar(select(TypoRef.cd_typo).where(TypoRef.cd_table == "TYPO_CH")) + CB_typo = DB.session.scalar( + select(TypoRef.cd_typo).where(TypoRef.cd_table == "TYPO_CORINE_BIOTOPES") ) # get cd_hab_sortie list from lb_code of selected Corine Biotope - cd_hab_sortie = ( - DB.session.query(Habref) - .filter(and_(Habref.lb_code == lb_code, Habref.cd_typo == CB_typo)) - .one() - .cd_hab + cd_hab_sortie = DB.session.scalar( + select(Habref.cd_hab).where(and_(Habref.lb_code == lb_code, Habref.cd_typo == CB_typo)) ) # get all cd_hab_entre corresponding to cd_hab_sortie - q_cd_hab_entre = ( - DB.session.query(CorespHab) - .filter( + q_cd_hab_entre = DB.session.scalars( + select(CorespHab).where( and_(CorespHab.cd_hab_sortie == cd_hab_sortie, CorespHab.cd_typo_entre == CH_typo) ) - .all() - ) + ).all() # get list of cd_hab_entre/lb_code/lb_hab_fr for each cahier habitat ch = [] for q in q_cd_hab_entre: - hab = DB.session.query(Habref).filter(Habref.cd_hab == q.cd_hab_entre).one() + hab = DB.session.scalar(select(Habref).where(Habref.cd_hab == q.cd_hab_entre)) ch.append( { "cd_hab": q.cd_hab_entre, "front_name": hab.lb_code + " - " + hab.lb_hab_fr, "lb_code": hab.lb_code, "lb_hab_fr": hab.lb_hab_fr, - "priority": DB.session.query(CorChStatus) - .filter(CorChStatus.lb_code == hab.lb_code) - .one() - .priority, + "priority": DB.session.scalar( + select(CorChStatus.priority) + .where(CorChStatus.lb_code == hab.lb_code) + .distinct() + ), } ) return ch @@ -137,11 +131,10 @@ def get_impact_list(): def get_impact_category(impact): # get mnemonique of id_impact_type if impact.CorImpactTypes.id_impact_type is not None: - return ( - DB.session.query(TNomenclatures) - .filter(TNomenclatures.id_nomenclature == impact.CorImpactTypes.id_impact_type) - .one() - .mnemonique + return DB.session.scalar( + select(TNomenclatures.mnemonique).where( + TNomenclatures.id_nomenclature == impact.CorImpactTypes.id_impact_type + ) ) return "Aucun" @@ -149,19 +142,16 @@ def get_impact_category(impact): def get_function_list(mnemo): try: # get id_type of mnemo (ex : 'FONCTIONS_HYDRO') in BibNomenclatureTypes - id_type_main_function = ( - DB.session.query(BibNomenclaturesTypes) - .filter(BibNomenclaturesTypes.mnemonique == mnemo) - .one() - .id_type + id_type_main_function = DB.session.scalar( + select(BibNomenclaturesTypes.id_type).where(BibNomenclaturesTypes.mnemonique == mnemo) ) # get list of TNomenclatures ids by id_type nomenclature_ids = [ nomenc.id_nomenclature - for nomenc in DB.session.query(TNomenclatures) - .filter(TNomenclatures.id_type == id_type_main_function) - .all() + for nomenc in DB.session.scalars( + select(TNomenclatures).where(TNomenclatures.id_type == id_type_main_function) + ).all() ] return [ @@ -169,10 +159,11 @@ def get_function_list(mnemo): "id_nomenclature": function.CorMainFct.id_function, "mnemonique": function.TNomenclatures.mnemonique, "id_category": function.CorMainFct.id_main_function, - "category": DB.session.query(TNomenclatures) - .filter(TNomenclatures.id_nomenclature == function.CorMainFct.id_main_function) - .one() - .mnemonique.upper(), + "category": DB.session.scalar( + select(TNomenclatures.mnemonique).where( + TNomenclatures.id_nomenclature == function.CorMainFct.id_main_function + ) + ).upper(), } for function in CorMainFct.get_functions(nomenclature_ids) ] @@ -187,19 +178,16 @@ def get_function_list(mnemo): def get_all_function_list(mnemo): try: # get id_type of mnemo (ex : 'FONCTIONS_HYDRO') in BibNomenclatureTypes - id_type_main_function = ( - DB.session.query(BibNomenclaturesTypes) - .filter(BibNomenclaturesTypes.mnemonique == mnemo) - .one() - .id_type - ) + id_type_main_function = DB.session.execute( + select(BibNomenclaturesTypes.id_type).where(BibNomenclaturesTypes.mnemonique == mnemo) + ).scalar_one() # get list of TNomenclatures ids by id_type nomenclature_ids = [ nomenc.id_nomenclature - for nomenc in DB.session.query(TNomenclatures) - .filter(TNomenclatures.id_type == id_type_main_function) - .all() + for nomenc in DB.session.scalars( + select(TNomenclatures).where(TNomenclatures.id_type == id_type_main_function) + ).all() ] return [ @@ -207,10 +195,13 @@ def get_all_function_list(mnemo): "id_nomenclature": function.CorMainFct.id_function, "mnemonique": function.TNomenclatures.mnemonique, "id_category": function.CorMainFct.id_main_function, - "category": DB.session.query(TNomenclatures) - .filter(TNomenclatures.id_nomenclature == function.CorMainFct.id_main_function) - .one() - .mnemonique.upper(), + "category": DB.session.execute( + select(TNomenclatures.mnemonique).where( + TNomenclatures.id_nomenclature == function.CorMainFct.id_main_function + ) + ) + .scalar_one() + .upper(), } for function in CorMainFct.get_all_functions(nomenclature_ids) ] @@ -245,21 +236,23 @@ def get_protections(): return [ { "id_protection_status": protection.id_protection_status, - "mnemonique_status": DB.session.query(TNomenclatures) - .filter(TNomenclatures.id_nomenclature == protection.id_protection_status) - .one() - .mnemonique, + "mnemonique_status": DB.session.scalar( + select(TNomenclatures.mnemonique).where( + TNomenclatures.id_nomenclature == protection.id_protection_status + ) + ), "id_protection_level": protection.id_protection_level, - "mnemonique_level": DB.session.query(TNomenclatures) - .filter(TNomenclatures.id_nomenclature == protection.id_protection_level) - .one() - .mnemonique, + "mnemonique_level": DB.session.scalar( + select(TNomenclatures.mnemonique).where( + TNomenclatures.id_nomenclature == protection.id_protection_level + ) + ), "category": get_protection_category(protection), "category_id": protection.id_protection_type, } - for protection in DB.session.query(CorProtectionLevelType) - .order_by(CorProtectionLevelType.id_protection) - .all() + for protection in DB.session.scalars( + select(CorProtectionLevelType).order_by(CorProtectionLevelType.id_protection) + ).all() ] except Exception as e: exc_type, value, tb = sys.exc_info() @@ -271,11 +264,10 @@ def get_protections(): def get_protection_category(protection): if protection.id_protection_type is not None: - return ( - DB.session.query(TNomenclatures) - .filter(TNomenclatures.id_nomenclature == protection.id_protection_type) - .one() - .mnemonique + return DB.session.scalar( + select(TNomenclatures.mnemonique).where( + TNomenclatures.id_nomenclature == protection.id_protection_type + ) ) return "Autre" diff --git a/backend/gn_module_zh/search.py b/backend/gn_module_zh/search.py index e7373ae6..c686c7eb 100644 --- a/backend/gn_module_zh/search.py +++ b/backend/gn_module_zh/search.py @@ -5,6 +5,7 @@ from pypnnomenclature.models import TNomenclatures from sqlalchemy import and_, desc, func, or_ from sqlalchemy.sql.expression import select +from sqlalchemy.orm import aliased from utils_flask_sqla.generic import GenericQuery from .api_error import ZHApiError @@ -40,7 +41,7 @@ def strip_accents(s): def main_search(query, json): for key in json.keys(): if key in TZH.__table__.columns: - query = query.filter(getattr(TZH, key) == json[key]) + query = query.where(getattr(TZH, key) == json[key]) sdage = json.get("sdage") if sdage is not None: query = filter_sdage(query, sdage) @@ -111,7 +112,7 @@ def main_search(query, json): def filter_sdage(query, json: dict): ids = [obj.get("id_nomenclature") for obj in json] - return query.filter(TZH.id_sdage.in_(ids)) + return query.where(TZH.id_sdage.in_(ids)) def filter_nameorcode(query, json: dict): @@ -120,19 +121,19 @@ def filter_nameorcode(query, json: dict): json = strip_accents(json) # TODO: create index with another function to make unaccent immutable unaccent_fullname = func.lower(func.unaccent(TZH.fullname)) - subquery = ( - DB.session.query(TZH.id_zh, func.similarity(unaccent_fullname, json).label("idx_trgm")) - .filter(unaccent_fullname.ilike("%" + json + "%")) + subq = ( + select(TZH.id_zh, func.similarity(unaccent_fullname, json).label("idx_trgm")) + .where(unaccent_fullname.ilike("%" + json + "%")) .order_by(desc("idx_trgm")) .subquery() ) - return query.filter(TZH.id_zh == subquery.c.id_zh) + return query.where(TZH.id_zh == subq.c.id_zh) return query def filter_ensemble(query, json: dict): ids = [obj.get("id_site_space") for obj in json] - return query.filter(TZH.id_site_space.in_(ids)) + return query.where(TZH.id_site_space.in_(ids)) def filter_area_size(query, json: dict): @@ -143,11 +144,11 @@ def filter_area_size(query, json: dict): # TZH.area is already in ha if symbol == "=": - query = query.filter(TZH.area == ha) + query = query.where(TZH.area == ha) elif symbol == "≥": - query = query.filter(TZH.area >= ha) + query = query.where(TZH.area >= ha) elif symbol == "≤": - query = query.filter(TZH.area <= ha) + query = query.where(TZH.area <= ha) return query @@ -159,17 +160,15 @@ def filter_area(query, json: dict, type_code: str): # Filter on departments subquery = ( - DB.session.query(LAreas) - .with_entities(LAreas.area_name, LAreas.geom, LAreas.id_type, BibAreasTypes.type_code) + select(LAreas.area_name, LAreas.geom, LAreas.id_type, BibAreasTypes.type_code) .join(BibAreasTypes, LAreas.id_type == BibAreasTypes.id_type) - .filter(BibAreasTypes.type_code == type_code) - .filter(LAreas.area_code.in_(codes)) + .where(BibAreasTypes.type_code == type_code, LAreas.area_code.in_(codes)) .subquery() ) # Filter on geom. # Need to use (c) on subquery to get the column - query = query.filter( + query = query.where( func.ST_Transform(func.ST_SetSRID(TZH.geom, 4326), 2154).ST_Intersects(subquery.c.geom) ) @@ -181,14 +180,13 @@ def filter_hydro(query, json): if codes and all(code is not None for code in codes): subquery = ( - DB.session.query(THydroArea) - .with_entities(THydroArea.id_hydro, THydroArea.geom) - .filter(THydroArea.id_hydro.in_(codes)) + select(THydroArea.id_hydro, THydroArea.geom) + .where(THydroArea.id_hydro.in_(codes)) .subquery() ) # SET_SRID does not return a valid geom... - query = query.filter( + query = query.where( func.ST_Transform(func.ST_SetSRID(TZH.geom, 4326), 4326).ST_Intersects(subquery.c.geom) ) @@ -200,16 +198,15 @@ def filter_basin(query, json): if codes is not None: subquery = ( - DB.session.query(TRiverBasin) - .with_entities( + select( TRiverBasin.id_rb, TRiverBasin.geom, ) - .filter(TRiverBasin.id_rb.in_(codes)) + .where(TRiverBasin.id_rb.in_(codes)) .subquery() ) # SET_SRID does not return a valid geom... - query = query.filter( + query = query.where( func.ST_Transform(func.ST_SetSRID(TZH.geom, 4326), 4326).ST_Intersects(subquery.c.geom) ) @@ -233,8 +230,8 @@ def filter_fct(query, json: dict, type_: str): ids_conn = [f.get("id_nomenclature") for f in json.get("connaissances", [])] subquery = ( - DB.session.query(TFunctions.id_zh) - .with_entities( + # TODO: be careful with this. To be verified + select( TFunctions.id_zh, TFunctions.id_function, TFunctions.id_qualification, @@ -245,19 +242,19 @@ def filter_fct(query, json: dict, type_: str): ) .join(TFunctions, TFunctions.id_zh == TZH.id_zh) .join(TNomenclatures, TNomenclatures.id_nomenclature == TFunctions.id_function) - .filter_by(id_type=select([func.ref_nomenclatures.get_id_nomenclature_type(type_)])) + .filter_by(id_type=select(func.ref_nomenclatures.get_id_nomenclature_type(type_))) ) if ids_fct and all(id_ is not None for id_ in ids_fct): - subquery = subquery.filter(TFunctions.id_function.in_(ids_fct)) + subquery = subquery.where(TFunctions.id_function.in_(ids_fct)) if ids_qual and all(id_ is not None for id_ in ids_qual): - subquery = subquery.filter(TFunctions.id_qualification.in_(ids_qual)) + subquery = subquery.where(TFunctions.id_qualification.in_(ids_qual)) if ids_conn and all(id_ is not None for id_ in ids_conn): - subquery = subquery.filter(TFunctions.id_knowledge.in_(ids_conn)) + subquery = subquery.where(TFunctions.id_knowledge.in_(ids_conn)) - query = query.filter(TZH.id_zh == subquery.subquery().c.id_zh).distinct() + query = query.where(TZH.id_zh == subquery.subquery().c.id_zh).distinct() return query @@ -266,12 +263,10 @@ def filter_statuts(query, json: dict): ids_statuts = [f.get("id_nomenclature") for f in json.get("statuts", [])] if ids_statuts: - subquery = ( - DB.session.query(TOwnership.id_zh) - .with_entities(TOwnership.id_zh, TOwnership.id_status) - .filter(TOwnership.id_status.in_(ids_statuts)) + subquery = select(TOwnership.id_zh, TOwnership.id_status).where( + TOwnership.id_status.in_(ids_statuts) ) - query = query.filter(TZH.id_zh == subquery.subquery().c.id_zh).distinct() + query = query.where(TZH.id_zh == subquery.subquery().c.id_zh).distinct() return query @@ -281,8 +276,7 @@ def filter_plans(query, json: dict): if ids_plans and all(id_ is not None for id_ in ids_plans): subquery = ( - DB.session.query(TManagementStructures.id_zh) - .with_entities( + select( TManagementPlans.id_nature, TManagementPlans.id_structure, TManagementStructures.id_structure, @@ -292,10 +286,10 @@ def filter_plans(query, json: dict): TManagementStructures, TManagementPlans.id_structure == TManagementStructures.id_structure, ) - .filter(TManagementPlans.id_nature.in_(ids_plans)) + .where(TManagementPlans.id_nature.in_(ids_plans)) ) - query = query.filter(TZH.id_zh == subquery.subquery().c.id_zh).distinct() + query = query.where(TZH.id_zh == subquery.subquery().c.id_zh).distinct() return query @@ -303,7 +297,7 @@ def filter_plans(query, json: dict): def filter_strategies(query, json: dict): ids_strategies = [f.get("id_nomenclature") for f in json.get("strategies", [])] if ids_strategies: - query = query.filter(TZH.id_strat_gestion.in_(ids_strategies)).distinct() + query = query.where(TZH.id_strat_gestion.in_(ids_strategies)).distinct() return query @@ -313,13 +307,13 @@ def filter_evaluations(query, json: dict): ids_menaces = [f.get("id_nomenclature") for f in json.get("menaces", [])] if ids_hydros and all(id_ is not None for id_ in ids_hydros): - query = query.filter(TZH.id_diag_hydro.in_(ids_hydros)) + query = query.where(TZH.id_diag_hydro.in_(ids_hydros)) if ids_bios and all(id_ is not None for id_ in ids_bios): - query = query.filter(TZH.id_diag_bio.in_(ids_bios)) + query = query.where(TZH.id_diag_bio.in_(ids_bios)) if ids_menaces and all(id_ is not None for id_ in ids_menaces): - query = query.filter(TZH.id_thread.in_(ids_menaces)) + query = query.where(TZH.id_thread.in_(ids_menaces)) return query @@ -348,9 +342,9 @@ def filter_hierarchy(query, json: dict, basin: str): filters.append(TZH.id_zh.in_(subquery)) if not and_: - query = query.filter(or_(*filters)) + query = query.where(or_(*filters)) else: - query = query.filter(*filters) + query = query.where(*filters) return query @@ -374,7 +368,7 @@ def generate_global_attributes_subquery(attributes: list, global_notes: dict): """ Generates the subquery taking care only on "GlobalMarks" """ - subquery = DB.session.query(CorZhNotes.id_zh) + subquery = select(CorZhNotes.id_zh) note_query = func.sum(CorZhNotes.note) subquery = subquery.join(CorRbRules, CorRbRules.cor_rule_id == CorZhNotes.cor_rule_id).join( @@ -406,7 +400,7 @@ def generate_global_attributes_subquery(attributes: list, global_notes: dict): def generate_volet(subquery, volet: str, attribute_list: list, global_notes: dict, note_query): if volet.lower() in [VOLET1.lower(), VOLET2.lower()]: - subquery = subquery.join(BibHierPanes, BibHierPanes.pane_id == TRules.pane_id).filter( + subquery = subquery.join(BibHierPanes, BibHierPanes.pane_id == TRules.pane_id).where( BibHierPanes.label == volet ) subquery = generate_volet_subquery( @@ -439,7 +433,7 @@ def generate_volet_subquery(subquery, volet, attribute_list: list, global_notes: def generate_rub(subquery, rub: str, attribute_list: list, global_notes: dict, note_query): - subquery = subquery.join(BibHierCategories, BibHierCategories.cat_id == TRules.cat_id).filter( + subquery = subquery.join(BibHierCategories, BibHierCategories.cat_id == TRules.cat_id).where( BibHierCategories.label == rub ) # Takes care of the several attributes choosen by the user. @@ -495,7 +489,7 @@ def generate_rub(subquery, rub: str, attribute_list: list, global_notes: dict, n def generate_attributes_subquery(attributes: list): - subquery = DB.session.query(CorZhNotes.id_zh) + subquery = select(CorZhNotes.id_zh) attribute_ids = [] note_type_ids = [] cor_rule_ids = [] @@ -507,11 +501,11 @@ def generate_attributes_subquery(attributes: list): notes.append(attribute["note"]) # TODO: see if all of these are usefull... Are cor_rule_id with note sufficient? - subquery = ( - subquery.filter(CorZhNotes.attribute_id.in_(attribute_ids)) - .filter(CorZhNotes.note_type_id.in_(note_type_ids)) - .filter(CorZhNotes.cor_rule_id.in_(cor_rule_ids)) - .filter(CorZhNotes.note.in_(notes)) + subquery = subquery.where( + CorZhNotes.attribute_id.in_(attribute_ids), + CorZhNotes.note_type_id.in_(note_type_ids), + CorZhNotes.cor_rule_id.in_(cor_rule_ids), + CorZhNotes.note.in_(notes), ) return subquery.subquery() diff --git a/backend/gn_module_zh/upload.py b/backend/gn_module_zh/upload.py index bc3e4ce6..f9ab229a 100644 --- a/backend/gn_module_zh/upload.py +++ b/backend/gn_module_zh/upload.py @@ -4,6 +4,7 @@ from geonature.core.gn_commons.models import TMedias from geonature.utils.env import DB, ROOT_DIR +from sqlalchemy.sql import update, select from werkzeug.utils import secure_filename from .api_error import ZHApiError @@ -101,8 +102,8 @@ def upload(request, extensions, pdf_size, jpg_size, upload_path, module_name, id return {"error": "ERROR_WHILE_LOADING_FILE"} # update TMedias.media_path with media_filename - DB.session.query(TMedias).filter(TMedias.id_media == id_media).update( - {"media_path": str(media_path)} + DB.session.execute( + update(TMedias).where(TMedias.id_media == id_media).values(media_path=str(media_path)) ) update_file_extension(id_media, extension) @@ -112,8 +113,8 @@ def upload(request, extensions, pdf_size, jpg_size, upload_path, module_name, id return { "file_name": get_file_path(id_media).name, "full_path": str(get_file_path(id_media)), - "media_path": getattr( - DB.session.query(TMedias).filter(TMedias.id_media == id_media).one(), "media_path" + "media_path": DB.session.scalar( + select(TMedias.media_path).where(TMedias.id_media == id_media) ), "extension": get_extension(get_file_path(id_media).name), } diff --git a/backend/gn_module_zh/utils.py b/backend/gn_module_zh/utils.py index d16d8785..7379bd4d 100644 --- a/backend/gn_module_zh/utils.py +++ b/backend/gn_module_zh/utils.py @@ -7,6 +7,7 @@ from geonature.utils.env import DB, ROOT_DIR from pypnnomenclature.models import TNomenclatures from sqlalchemy.orm import Query +from sqlalchemy.sql import select, update, delete, func from .api_error import ZHApiError from .model.zh_schema import TZH, BibAreasTypes, LAreas @@ -18,12 +19,12 @@ def get_main_picture_id(id_zh, media_list=None): media_list(list): media_list of the zh to set the main_pict_id if not present """ - main_pict_id = DB.session.query(TZH).filter(TZH.id_zh == id_zh).one().main_pict_id + main_pict_id = DB.session.scalar(select(TZH.main_pict_id).where(TZH.id_zh == id_zh)) if main_pict_id is None and media_list is not None and len(media_list) > 0: id_media = media_list[0].id_media - DB.session.query(TZH).filter(TZH.id_zh == id_zh).update({TZH.main_pict_id: id_media}) + stmt = update(TZH).where(TZH.id_zh == id_zh).values(main_pict_id=id_media) + DB.session.execute(stmt) DB.session.commit() - main_pict_id = id_media return main_pict_id @@ -35,17 +36,20 @@ def get_last_pdf_export(id_zh, last_date) -> Query: """ # TODO: Add with entities ? # Need to have do a separate query instead of reusing get_medias... + # TODO : compare efficiency with or without join query = ( - DB.session.query(TZH, TMedias, TNomenclatures) - .with_entities(TMedias.id_media) - .filter(TZH.id_zh == id_zh) - .filter(TZH.zh_uuid == TMedias.unique_id_media) - .filter(TMedias.id_nomenclature_media_type == TNomenclatures.id_nomenclature) - .filter(TNomenclatures.mnemonique == "PDF") - .filter(TMedias.meta_update_date > last_date) - .filter(TMedias.title_fr.like(f"{id_zh}_fiche%.pdf")) + select(TZH, TMedias, TNomenclatures) + .with_only_columns(TMedias.id_media) + .where( + TZH.id_zh == id_zh, + TZH.zh_uuid == TMedias.unique_id_media, + TMedias.id_nomenclature_media_type == TNomenclatures.id_nomenclature, + TNomenclatures.mnemonique == "PDF", + TMedias.meta_update_date > last_date, + TMedias.title_fr.like(f"{id_zh}_fiche%.pdf"), + ) ) - return query.first() + return DB.session.execute(query).first() def get_file_path(id_media): @@ -61,7 +65,7 @@ def get_file_path(id_media): def get_media_path(id_media): try: - return DB.session.query(TMedias).filter(TMedias.id_media == id_media).one().media_path + return DB.session.get(TMedias, id_media).media_path except Exception as e: exc_type, value, tb = sys.exc_info() raise ZHApiError( @@ -76,7 +80,8 @@ def delete_file(id_media): os.remove(get_file_path(id_media)) except: pass - DB.session.query(TMedias).filter(TMedias.id_media == id_media).delete() + stmt = delete(TMedias).where(TMedias.id_media == id_media) + DB.session.execute(stmt) DB.session.commit() except Exception as e: exc_type, value, tb = sys.exc_info() @@ -87,14 +92,14 @@ def delete_file(id_media): def check_ref_geo_schema(): try: - id_type_com = ( - DB.session.query(BibAreasTypes).filter(BibAreasTypes.type_code == "COM").one().id_type + id_type_com = DB.session.scalar( + select(BibAreasTypes.id_type).where(BibAreasTypes.type_code == "COM") ) - id_type_dep = ( - DB.session.query(BibAreasTypes).filter(BibAreasTypes.type_code == "DEP").one().id_type + id_type_dep = DB.session.scalar( + select(BibAreasTypes.id_type).where(BibAreasTypes.type_code == "DEP") ) - n_com = DB.session.query(LAreas).filter(LAreas.id_type == id_type_com).count() - n_dep = DB.session.query(LAreas).filter(LAreas.id_type == id_type_dep).count() + n_com = DB.session.scalar(select(func.count()).where(LAreas.id_type == id_type_com)) + n_dep = DB.session.scalar(select(func.count()).where(LAreas.id_type == id_type_dep)) if n_com == 0 or n_dep == 0: return False return True