data_definition_options() used to exclude relation-type fields from its field list entirely, so a filter/binding could never reference "the linked object" of a row — and even when a relation field's clean name was typed manually (as the earlier "level.parcour" example needed), it silently matched nothing: every column lookup for a filter/repeater field used the field's own name, but a relation is actually stored in a "<field>_id" column (see create_definition.py), so the lookup always missed.
Relation fields now appear in the champ dropdowns (Répéteur's filtre_champ/filtre2_champ, Donnée liée's data_filtre_champ/data_filtre2_champ) labeled with the object they point to (e.g. "parcour (→ parcours)"), and a new _field_column() helper in filter_repeater_rows.py resolves the right "<field>_id" column whenever the field turns out to be a relation — used consistently by the filter comparison itself, the "{{Objet.champ}}" dynamic-value resolver, the repeater's row content ({{champ}}), and the Donnée liée row context. Jauge's own champ/champ_nom pickers (which need an actual displayable value, not an id) still exclude relations, both server- and client-side.
Verified end to end: the dropdown shows the relation field with its target-object label, and filtering "level" rows by the clean relation field name "parcour" (not "parcour_id") against a dynamic {{game.current_parcours}} reference now actually matches, alongside the existing "number" filter. Full suite green (89).
39 lines
1.8 KiB
Python
39 lines
1.8 KiB
Python
import db
|
|
|
|
from .filter_repeater_rows import filter_repeater_rows, _field_column
|
|
|
|
|
|
def _resolve_bound_row_ctx(slug, attrs):
|
|
"""Si cet élément est lié à un objet de données (attr:_data_definition_id —
|
|
réglage "Lier à un objet de données" des widgets Texte/Titre, voir
|
|
DATA_BINDING_CONTROLS), retrouve LA ligne qui correspond aux 1 ou 2
|
|
filtres réglés (_data_filtre*/_data_filtre2*) — même moteur que le
|
|
filtre du Répéteur de données, voir filter_repeater_rows.py — et
|
|
renvoie ses champs sous forme de {nom_du_champ: valeur en texte},
|
|
exploitable par {{champ}} dans le contenu. Permet d'afficher UNE seule
|
|
valeur calculée (ex: l'objectif du niveau en cours) sans avoir besoin de
|
|
poser un Répéteur, qui affiche lui plusieurs lignes. Renvoie None si
|
|
rien n'est lié ou si aucune ligne ne correspond."""
|
|
definition_id = attrs.get("_data_definition_id")
|
|
if not definition_id or not slug:
|
|
return None
|
|
try:
|
|
definition = db.get_definition(slug, int(definition_id))
|
|
except (TypeError, ValueError):
|
|
return None
|
|
if not definition:
|
|
return None
|
|
rows = db.list_rows(slug, definition)
|
|
rows = filter_repeater_rows(slug, definition, rows, {
|
|
"_filtre_champ": attrs.get("_data_filtre_champ"),
|
|
"_filtre_operateur": attrs.get("_data_filtre_operateur"),
|
|
"_filtre_valeur": attrs.get("_data_filtre_valeur"),
|
|
"_filtre2_champ": attrs.get("_data_filtre2_champ"),
|
|
"_filtre2_operateur": attrs.get("_data_filtre2_operateur"),
|
|
"_filtre2_valeur": attrs.get("_data_filtre2_valeur"),
|
|
})
|
|
if not rows:
|
|
return None
|
|
row = rows[0]
|
|
return {f["name"]: str(row.get(_field_column(definition, f["name"]), "") or "") for f in definition["fields"]}
|