Repository: PnX-SI/TaxHub (language: python)

Issue:
feat: improve perf route biblistes
- Load only necessary fields
- Remove useless parameter id=None
- Fix expression "nb_taxons" in BibListes model

See issue : #584 

Reviewed-by: andriacap


Discussion / hints:

Fix patch:
diff --git a/apptax/taxonomie/models.py b/apptax/taxonomie/models.py
index ac7e2663..df62c506 100644
--- a/apptax/taxonomie/models.py
+++ b/apptax/taxonomie/models.py
@@ -261,13 +261,17 @@ class BibListes(db.Model):
 
     @hybrid_property
     def nb_taxons(self):
-        return len(self.noms)
+        return db.session.scalar(
+            select([db.func.count(cor_nom_liste.c.cd_nom)]).where(
+                cor_nom_liste.c.id_liste == self.id_liste
+            )
+        )
 
     @nb_taxons.expression
     def nb_taxons(cls):
         return (
-            db.select([db.func.count(cor_nom_liste.id_liste)])
-            .where(BibListes.id_liste == cls.id_liste)
+            db.select([db.func.count(cor_nom_liste.c.cd_nom)])
+            .where(cor_nom_liste.c.id_liste == cls.id_liste)
             .label("nb_taxons")
         )
 
diff --git a/apptax/taxonomie/routesbiblistes.py b/apptax/taxonomie/routesbiblistes.py
index 512764c9..f0652634 100644
--- a/apptax/taxonomie/routesbiblistes.py
+++ b/apptax/taxonomie/routesbiblistes.py
@@ -3,16 +3,13 @@
 import os
 import logging
 
-from flask import Blueprint, request, current_app
-from sqlalchemy import func, or_
-from sqlalchemy.orm import joinedload
+from flask import Blueprint
+from sqlalchemy import select
 
-from pypnusershub import routes as fnauth
 from utils_flask_sqla.response import json_resp
 
-from . import filemanager
 from . import db
-from .models import BibListes, Taxref
+from .models import BibListes
 from apptax.taxonomie.schemas import BibListesSchema
 
 adresses = Blueprint("bib_listes", __name__)
@@ -24,26 +21,38 @@
 
 @adresses.route("/", methods=["GET"])
 @json_resp
-def get_biblistes(id=None):
+def get_biblistes():
     """
     retourne les contenu de bib_listes dans "data"
     et le nombre d'enregistrements dans "count"
     """
-    data = db.session.query(BibListes).all()
+    biblistes_records = db.session.execute(
+        select(
+            BibListes.id_liste,
+            BibListes.code_liste,
+            BibListes.nom_liste,
+            BibListes.desc_liste,
+            BibListes.nb_taxons,
+            BibListes.regne,
+            BibListes.group2_inpn,
+        )
+    ).all()
     biblistes_schema = BibListesSchema()
-    maliste = {"data": [], "count": 0}
-    maliste["count"] = len(data)
-    maliste["data"] = biblistes_schema.dump(data, many=True)
-    return maliste
+    biblistes_infos = {
+        "data": biblistes_schema.dump(biblistes_records, many=True),
+        "count": len(biblistes_records),
+    }
+
+    return biblistes_infos
 
 
 @adresses.route("/<regne>", methods=["GET"], defaults={"group2_inpn": None})
 @adresses.route("/<regne>/<group2_inpn>", methods=["GET"])
 def get_biblistesbyTaxref(regne, group2_inpn):
-    q = db.session.query(BibListes)
+    q = select(BibListes)
     if regne:
         q = q.where(BibListes.regne == regne)
     if group2_inpn:
         q = q.where(BibListes.group2_inpn == group2_inpn)
-    results = q.all()
+    results = db.session.scalars(q).all()
     return BibListesSchema().dump(results, many=True)


Test patch:
diff --git a/apptax/tests/fixtures.py b/apptax/tests/fixtures.py
index e35103e7..aec6503f 100644
--- a/apptax/tests/fixtures.py
+++ b/apptax/tests/fixtures.py
@@ -95,7 +95,14 @@ def liste():
         "code_liste": "TEST_LIST_Plantae",
         "nom_liste": "Liste test Plantae",
         "desc_liste": "Liste description",
-        "regne": "Plantea",
+        "regne": "Plantae",
+    },
+    {
+        "code_liste": "TEST_LIST_Mousses",
+        "nom_liste": "Liste test Mousses",
+        "desc_liste": "Liste description",
+        "regne": "Plantae",
+        "group2_inpn": "Mousses",
     },
 ]
 
diff --git a/apptax/tests/test_biblistes.py b/apptax/tests/test_biblistes.py
index 3e7c161f..784c293b 100644
--- a/apptax/tests/test_biblistes.py
+++ b/apptax/tests/test_biblistes.py
@@ -8,22 +8,13 @@
 
 @pytest.mark.usefixtures("client_class", "temporary_transaction")
 class TestApiBibListe:
-    schema_cor_nom_liste = Schema(
-        {
-            "items": [{"cd_nom": int, "id_liste": int}],
-            "total": int,
-            "limit": int,
-            "page": int,
-        }
-    )
-
     schema_allnamebyListe = Schema(
         [
             {
                 "id_liste": int,
                 "code_liste": str,
                 "nom_liste": str,
-                "desc_liste": str,
+                "desc_liste": Or(str, None),
                 "regne": Or(str, None),
                 "group2_inpn": Or(str, None),
                 "nb_taxons": int,
@@ -31,7 +22,7 @@ class TestApiBibListe:
         ]
     )
 
-    def test_get_biblistes(self):
+    def test_get_biblistes(self, listes):
         query_string = {"limit": 10}
         response = self.client.get(
             url_for(
@@ -45,7 +36,6 @@ def test_get_biblistes(self):
             assert self.schema_allnamebyListe.is_valid(data["data"])
 
     def test_get_biblistesbyTaxref(self, listes):
-
         response = self.client.get(
             url_for("bib_listes.get_biblistesbyTaxref", regne="Animalia", group2_inpn=None),
         )
@@ -53,3 +43,11 @@ def test_get_biblistesbyTaxref(self, listes):
         data = [d for d in response.json if d["desc_liste"] == "Liste description"]
         self.schema_allnamebyListe.validate(data)
         assert len(data) == 1
+
+        response = self.client.get(
+            url_for("bib_listes.get_biblistesbyTaxref", regne="Plantae", group2_inpn="Mousses"),
+        )
+        # Filter test list only
+        data = [d for d in response.json if d["desc_liste"] == "Liste description"]
+        self.schema_allnamebyListe.validate(data)
+        assert len(data) == 1