Skip to content

Commit

Permalink
Merge pull request #413 from PnX-SI/admin_filters
Browse files Browse the repository at this point in the history
filters from database list
  • Loading branch information
TheoLechemia authored Aug 1, 2023
2 parents df2ddab + 2417942 commit eed685a
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 58 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
*~

static/medias/*

node_modules
#taxhub app
settings.ini
venv
Expand Down
75 changes: 33 additions & 42 deletions apptax/admin/admin_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
from flask_admin.form.fields import Select2Field, JSONField

from flask_admin.model.template import EndpointLinkRowAction
from flask_admin.contrib.sqla.filters import BaseSQLAFilter

from sqlalchemy import or_
from wtforms import Form, BooleanField, SelectField, PasswordField, SubmitField, StringField
Expand All @@ -51,6 +50,14 @@
from pypnusershub.utils import get_current_app_id
from apptax.admin.admin import adresses
from apptax.admin.utils import PopulateBibListeException, populate_bib_liste
from apptax.admin.filters import (
TaxrefDistinctFilter,
FilterTaxrefAttr,
FilterBiblist,
FilterIsValidName,
FilterMedia,
FilterAttributes,
)


class FlaskAdminProtectedMixin:
Expand Down Expand Up @@ -191,36 +198,6 @@ def import_cd_nom_view(self, *args, **kwargs):
return self.render("admin/populate_biblist.html", form=form)


class FilterTaxrefAttr(BaseSQLAFilter):
def apply(self, query, value, alias=None):
if not has_app_context() or not has_request_context():
return ()
return query.join(CorTaxonAttribut).filter(CorTaxonAttribut.id_attribut == value)

def operation(self):
return "equals"

def get_options(self, view):
if not has_app_context() or not has_request_context():
return ()
return [(attr.id_attribut, attr.label_attribut) for attr in BibAttributs.query.all()]


class FilterBibList(BaseSQLAFilter):
def apply(self, query, value, alias=None):
if not has_app_context() or not has_request_context():
return ()
return query.join(CorNomListe).join(BibListes).filter(BibListes.id_liste == value)

def operation(self):
return "equals"

def get_options(self, view):
if not has_app_context() or not has_request_context():
return ()
return [(list.id_liste, list.nom_liste) for list in BibListes.query.all()]


class InlineMediaForm(InlineFormAdmin):
form_label = "Médias"

Expand Down Expand Up @@ -299,22 +276,38 @@ class TaxrefView(
"famille",
)

def _apply_search(self, query, count_query, joins, count_joins, search):
"""
Apply search to the autocomplete query
"""
query = query.filter(Taxref.cd_nom == int(search))
count_query = count_query.filter(Taxref.cd_nom == int(search))
return query, count_query, joins, count_joins

column_searchable_list = ["nom_complet", "cd_nom"]

column_filters = [
"regne",
"group2_inpn",
"classe",
"ordre",
"famille",
FilterBibList(
TaxrefDistinctFilter(column=Taxref.regne, name="Règne"),
TaxrefDistinctFilter(column=Taxref.group2_inpn, name="Group2 INPN"),
TaxrefDistinctFilter(column=Taxref.classe, name="Classe"),
FilterBiblist(
column="liste",
name="Est dans la liste",
),
FilterTaxrefAttr(
column="attributs",
name="A l'attribut",
),
FilterIsValidName(
name="Nom valide / synonyme", options=[(1, "Nom valide"), (0, "Synonyme")]
),
FilterMedia(
name="Média", options=[(1, "Possède un média"), (0, "Ne possède pas de média")]
),
FilterAttributes(
name="Attributs",
options=[(1, "Possède un attribut"), (0, "Ne possède pas d'attribut")],
),
]
column_formatters = {c: macro("render_nom_ref") for c in column_list}

Expand All @@ -325,17 +318,16 @@ class TaxrefView(
edit_template = "admin/edit_taxref.html"
details_template = "admin/details_taxref.html"

def _get_theme_attributes(self, taxon_name):
def _get_theme_attributes(self, taxon):
return (
db.session.query(BibThemes)
.filter(or_(BibAttributs.v_regne == taxon_name.regne, BibAttributs.v_regne == None))
.filter(or_(BibAttributs.v_regne == taxon.regne, BibAttributs.v_regne == None))
.filter(
or_(
BibAttributs.v_group2_inpn == taxon_name.group2_inpn,
BibAttributs.v_group2_inpn == taxon.group2_inpn,
BibAttributs.v_group2_inpn == None,
)
)
.filter(BibAttributs.id_theme == BibThemes.id_theme)
.order_by(BibAttributs.ordre)
.all()
)
Expand Down Expand Up @@ -382,7 +374,6 @@ def edit_view(self):

# Get attributes
theme_attributs_def = self._get_theme_attributes(taxon_name)
print(theme_attributs_def)
attributes_val = self._get_attributes_value(taxon_name, theme_attributs_def)
if request.method == "POST":
for f in request.form:
Expand Down
99 changes: 99 additions & 0 deletions apptax/admin/filters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
from functools import partial

from flask import has_app_context
from flask_admin.model.filters import BaseFilter

from flask_admin.contrib.sqla.filters import FilterEqual
from flask_admin.babel import lazy_gettext


from apptax.taxonomie.models import (
Taxref,
BibAttributs,
CorTaxonAttribut,
BibListes,
CorNomListe,
TMedias,
)


# https://github.com/flask-admin/flask-admin/issues/1807
# https://stackoverflow.com/questions/54638047/correct-way-to-register-flask-admin-views-with-application-factory
class ReloadingIterator:
def __init__(self, iterator_factory):
self.iterator_factory = iterator_factory

def __iter__(self):
return self.iterator_factory()


class DynamicOptionsMixin:
def get_dynamic_options(self, view):
raise NotImplementedError

def get_options(self, view):
return ReloadingIterator(partial(self.get_dynamic_options, view))


class TaxrefDistinctFilter(DynamicOptionsMixin, FilterEqual):
def get_dynamic_options(self, view):
if has_app_context():
yield from [
(getattr(row, self.column.key), getattr(row, self.column.key))
for row in Taxref.query.distinct(self.column).order_by(self.column).all()
]


class FilterTaxrefAttr(DynamicOptionsMixin, FilterEqual):
def apply(self, query, value, alias=None):
return query.join(CorTaxonAttribut).filter(CorTaxonAttribut.id_attribut == value)

def get_dynamic_options(self, view):
if has_app_context():
yield from [
(attr.id_attribut, attr.label_attribut) for attr in BibAttributs.query.all()
]


class FilterBiblist(DynamicOptionsMixin, FilterEqual):
def apply(self, query, value, alias=None):
return query.join(CorNomListe).filter(CorNomListe.id_liste == value)

def get_dynamic_options(self, view):
if has_app_context():
yield from [(list.id_liste, list.nom_liste) for list in BibListes.query.all()]


class FilterIsValidName(BaseFilter):
def apply(self, query, value, alias=None):
if int(value) == 1:
return query.filter(Taxref.cd_nom == Taxref.cd_ref)
else:
return query.filter(Taxref.cd_nom != Taxref.cd_ref)

def operation(self):
return lazy_gettext("equal")


class FilterMedia(BaseFilter):
def apply(self, query, value, alias=None):
medias_filter = Taxref.medias.any()
if int(value) == 1:
return query.filter(medias_filter)
else:
return query.filter(~medias_filter)

def operation(self):
return lazy_gettext("equal")


class FilterAttributes(BaseFilter):
def apply(self, query, value, alias=None):
attr_filter = Taxref.attributs.any()
if int(value) == 1:
return query.filter(attr_filter)
else:
return query.filter(~attr_filter)

def operation(self):
return lazy_gettext("equal")
30 changes: 15 additions & 15 deletions apptax/admin/static/js/taxref_autocomplete.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
$(document).ready(function() {
let search = document.getElementById("search_value").value;
let url = (APPLICATION_ROOT + "/api/taxref/search/lb_nom/").replace("//", "/");
$(document).ready(function () {
let search = document.getElementById("search_value").value;
let url = (APPLICATION_ROOT + "api/taxref/allnamebylist").replace("//", "/");
$(".taxref-autocomplete").select2({
ajax: {
url: function (params) {
console.log(params)
if (search !==undefined && params == "") {
if (search !== undefined && params == "") {
params = search;
}
return url + params
return url + "?search_name=" + params;
},
results: function (data, page) {
var data = $.map(data, function (obj) {
obj.id = obj.id || obj.lb_nom;
obj.text = obj.text || obj.lb_nom;
var search_name = obj.search_name.replace("<i>", "");
search_name = search_name.replace("</i>", "");
obj.id = obj.cd_nom;
obj.text = search_name;
return obj;
});
return {results : data}
return { results: data };
},
dataType: 'json',
delay: 250,
placeholder: "Saisir les trois premières lettres du nom d'un taxon",
minimumInputLength: 3
},
dataType: "json",
delay: 250,
placeholder: "Nom latin, nom vernaculaire, cd_nom",
minimumInputLength: 3,
});

})
});
2 changes: 1 addition & 1 deletion apptax/taxonomie/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ class CorNomListe(db.Model):
primary_key=True,
)

taxref = db.relationship("Taxref")
# backref : Medias et Attributs

bib_liste = db.relationship("BibListes")

Expand Down

0 comments on commit eed685a

Please sign in to comment.