diff --git a/apptax/admin/admin_view.py b/apptax/admin/admin_view.py index 88bed887..b7dce594 100644 --- a/apptax/admin/admin_view.py +++ b/apptax/admin/admin_view.py @@ -13,7 +13,8 @@ from flask_admin.model.form import InlineFormAdmin from flask_admin.model.ajax import AjaxModelLoader, DEFAULT_PAGE_SIZE from flask_admin.contrib.sqla.filters import FilterEqual - +from flask_admin.form.widgets import Select2Widget +from flask_admin.contrib.sqla.fields import QuerySelectField from flask_admin.base import expose from flask_admin.model.helpers import get_mdict_item_or_list @@ -23,7 +24,7 @@ from flask_admin.model.template import EndpointLinkRowAction, TemplateLinkRowAction from flask_admin.model.template import EndpointLinkRowAction, TemplateLinkRowAction -from sqlalchemy import or_, inspect, select, func, exists +from sqlalchemy import or_, inspect, select, exists from sqlalchemy.orm import undefer @@ -39,7 +40,6 @@ CorTaxonAttribut, TMedias, BibListes, - VMRegne, cor_nom_liste, ) from apptax.admin.utils import taxref_media_file_name, get_user_permission @@ -55,6 +55,7 @@ FilterMedia, FilterAttributes, ) +from apptax.admin.mixins import RegneAndGroupFormMixin log = logging.getLogger(__name__) @@ -156,7 +157,7 @@ def can_delete(self): form_excluded_columns = ["attributs"] -class BibListesView(FlaskAdminProtectedMixin, ModelView): +class BibListesView(FlaskAdminProtectedMixin, RegneAndGroupFormMixin, ModelView): @property def can_create(self): return self._can_action(6) @@ -186,21 +187,9 @@ def can_delete(self): TemplateLinkRowAction("custom_row_actions.truncate_bib_liste", "Effacer cd_nom liste"), ] - form_args = { - "regne": { - "query_factory": lambda: db.session.scalars( - select(VMRegne).where(VMRegne.regne.isnot(None)) - ) - } - } - create_template = "admin/edit_bib_list.html" + form_columns = ["code_liste", "nom_liste", "desc_liste", "regne", "group2_inpn"] - def on_model_change(self, form, model, is_created): - """ - Force None on empty string regne - """ - if model.regne and not model.regne.regne: - model.regne = None + create_template = "admin/edit_bib_list.html" def render(self, template, **kwargs): self.extra_js = [ @@ -262,7 +251,9 @@ def import_cd_nom_view(self, *args, **kwargs): return redirect(self.get_url(".index_view")) - return self.render("admin/populate_biblist.html", form=form) + return self.render( + "admin/populate_biblist.html", form=form, return_url=self.get_url(".index_view") + ) class InlineMediaForm(InlineFormAdmin): @@ -331,6 +322,9 @@ def _apply_search(self, query, count_query, joins, count_joins, search): column_searchable_list = ["nom_complet", "cd_nom"] + # ATTENTION : les tests se basent sur les indices + # de ce tableau. Rajouter des filtres à la fin, ou changer les + # indice des filtres dans les tests (fonction `get_list`) column_filters = [ FilterEqual(Taxref.cd_nom, name="cd_nom"), FilterEqual(Taxref.cd_ref, name="cd_ref"), @@ -368,11 +362,11 @@ def _apply_search(self, query, count_query, joins, count_joins, search): def _get_theme_attributes(self, taxon): return ( db.session.query(BibThemes) - .filter(or_(BibAttributs.v_regne == taxon.regne, BibAttributs.v_regne == None)) + .filter(or_(BibAttributs.regne == taxon.regne, BibAttributs.regne == None)) .filter( or_( - BibAttributs.v_group2_inpn == taxon.group2_inpn, - BibAttributs.v_group2_inpn == None, + BibAttributs.group2_inpn == taxon.group2_inpn, + BibAttributs.group2_inpn == None, ) ) .order_by(BibAttributs.ordre) @@ -558,7 +552,7 @@ def get_list(self, query, offset=0, limit=DEFAULT_PAGE_SIZE): return Taxref.query.with_entities(Taxref.regne).distinct().all() -class BibAttributsView(FlaskAdminProtectedMixin, ModelView): +class BibAttributsView(FlaskAdminProtectedMixin, RegneAndGroupFormMixin, ModelView): form_base_class = TAdditionalAttributForm @@ -590,8 +584,6 @@ def can_delete(self): "group2_inpn", ) - create_template = "admin/edit_attr.html" - column_labels = { "desc_attribut": "Description", "regne": "Règne", @@ -604,11 +596,17 @@ def can_delete(self): "liste_valeur_attribut": """Doit suivre le format suivant: {"values":[valeur1, valeur2, valeur3]}""" } + def liste_valeur_attribut_formater(v, c, m, p): + if m.liste_valeur_attribut: + data = json.loads(m.liste_valeur_attribut) + if "values" in data: + return ", ".join(data["values"]) + return "" + column_formatters = { - "liste_valeur_attribut": lambda v, c, m, p: ", ".join( - json.loads(m.liste_valeur_attribut)["values"] - ), + "liste_valeur_attribut": liste_valeur_attribut_formater, } + create_template = "admin/edit_attr.html" def render(self, template, **kwargs): self.extra_js = [ @@ -617,13 +615,6 @@ def render(self, template, **kwargs): return super(BibAttributsView, self).render(template, **kwargs) - def on_model_change(self, form, model, is_created): - """ - Force None on empty string regne - """ - if model.regne and not model.regne.regne: - model.regne = None - form_choices = { "type_attribut": [ ("int", "int"), @@ -639,11 +630,3 @@ def on_model_change(self, form, model, is_created): ("text", "text"), ], } - - form_args = { - "regne": { - "query_factory": lambda: db.session.scalars( - select(VMRegne).where(VMRegne.regne.isnot(None)) - ) - } - } diff --git a/apptax/admin/mixins.py b/apptax/admin/mixins.py new file mode 100644 index 00000000..9e34c0c0 --- /dev/null +++ b/apptax/admin/mixins.py @@ -0,0 +1,50 @@ +from flask_admin.contrib.sqla.fields import QuerySelectField +from flask_admin.form.fields import Select2Field +from sqlalchemy import select + +from apptax.database import db +from apptax.taxonomie.models import VMRegne, VMGroup2Inpn + +from flask_admin.contrib.sqla.fields import QuerySelectField +from flask_admin.form.fields import Select2Field +from sqlalchemy import select + +from apptax.database import db +from apptax.taxonomie.models import VMRegne, VMGroup2Inpn + + +class RegneAndGroupFormMixin: + form_overrides = {"regne": QuerySelectField, "group2_inpn": QuerySelectField} + + form_args = { + "regne": { + "query_factory": lambda: db.session.scalars( + select(VMRegne).where(VMRegne.regne.isnot(None)) + ).all(), + "allow_blank": True, + }, + "group2_inpn": { + "query_factory": lambda: db.session.scalars( + select(VMGroup2Inpn).where(VMGroup2Inpn.group2_inpn.isnot(None)) + ), + "allow_blank": True, + }, + } + + def on_model_change(self, form, model, is_created): + """ + Force None on empty string regne + and put transform orm object in str + """ + # HACK otherwise QuerySelectField insert the VRegne object .. + # Select2Fields with choices does not work because choices list + # is load when app is loaded (its a probleme for migrations) + if model.regne: + model.regne = model.regne.regne + if model.regne == "": + model.regne = None + + if model.group2_inpn: + model.group2_inpn = model.group2_inpn.group2_inpn + if model.group2_inpn == "": + model.group2_inpn = None diff --git a/apptax/admin/templates/admin/details_taxref.html b/apptax/admin/templates/admin/details_taxref.html index 6fa49898..ce9543c5 100644 --- a/apptax/admin/templates/admin/details_taxref.html +++ b/apptax/admin/templates/admin/details_taxref.html @@ -124,7 +124,8 @@