Créer automatiquement le nombre de lignes voulu

Voici mon cas d’usage et le bouton d’action que j’ai mis en place pour y répondre.

Je décris dans une table Projets les projets que je gère, et dans une table Reporting les rapports (livrables) prévus pour chaque projet. Les projets font l’objet d’une contractualisation et parfois je dois fournir 2 rapports (intermédiaire et final), parfois 3 (rapport annuel), etc.

Plutôt que de tout créer à la main, j’ajoute dans la table Projets une colonne Nombre de rapportsqui va déterminer le nombre de lignes à créer dans la table Reporting. J’ajoute un bouton d’action… et voilà le tour est joué !

Voici la formule du bouton d’action :

actions = []

for r in Projets.all:
    if r.Nombre_de_rapports:  # Vérifie qu'il y a bien un nombre défini
        for i in range(1, r.Nombre_de_rapports + 1):
            actions.append(["AddRecord", "Reporting", None,
            {
            "Rapport": f"Rapport {i}",
            "Projet": r.id
            }
            ])
return {
    "button": "Créer les rapports",
    "description": "Le bouton ajoute une ligne par rapport",
    "actions": actions
}

Le Grist démo est ici : https://grist.numerique.gouv.fr/o/docs/77wFVPWmH8pg/Test-generation-de-lignes/p/1

Bonus : non seulement l’utilisateur est content que la création de lignes soit automatisée, mais il est encore plus content que les projets et les rapports soient gérées dans des tables séparées. En effet, avant Grist, il était obligé de gérer dans une méga-table les projets et les rapports, avec de nombreuses colonnes vides… le cauchemar !

4 « J'aime »

Mise à jour du bouton d’action dans la démo : il peut désormais ajuster les lignes en fonction du nombre de rapports attendu, soit en créant les lignes manquantes, soit en supprimant les lignes surnuméraires.

Voici le code correspondant :

actions = []

for r in Projets.all:
    if not r.Nombre_de_rapports or r.Nombre_de_rapports < 0:
        continue  # ignore les projets sans Nombre_de_rapports défini

    # Toutes les lignes Reporting associées à ce projet
    reporting_records = Reporting.lookupRecords(Projet=r)

    # Définir le nombre de lignes attendues et le nombre de lignes existantes
    count_rp_records = len(reporting_records)
    desired = r.Nombre_de_rapports

    # Si on doit AJOUTER des lignes
    if desired > count_rp_records:
      for i in range(count_rp_records + 1, r.Nombre_de_rapports + 1):
        actions.append([
          "AddRecord", "Reporting", None,
          {"Rapport": f"Rapport {i}",
          "Projet": r.id
          }
        ])

    # Si on doit SUPPRIMER des lignes
    elif desired < count_rp_records:
        to_delete = [
            rep.id for rep in reporting_records
            if rep.Rapport and rep.Rapport.startswith("Rapport ")
            and int(rep.Rapport.replace("Rapport ", "")) > desired
        ]
        for rep_id in to_delete:
            actions.append(["RemoveRecord", "Reporting", rep_id])

return {
    "button": "Mettre à jour les rapports",
    "description": "Ajuste le nombre de lignes selon le nombre de rapports prévus pour chaque projet",
    "actions": actions
}

Merci beaucoup pour cette ressource !
Ce serait très utile pour mon cas d’usage. J’ai donc tenté de le mettre en place, cependant, je rencontre deux problématiques sans réussir à mettre le doigt sur ce qui coince… À savoir qu’ayant aucune connaissance en code, je m’appuie aussi sur des IA pour m’aider à adapter le canva.

1- Lorsque j’injecte le code dans ma colonne « BOUTON ACTION » et que je configure le widget pour se « brancher » à cette colonne, il me renvoie :

« BOUTON_ACTION » cells should contain an object with keys « button », « description », « actions ». Missing keys: « button », « description », « actions ».

Alors que les objets figurent bien dans le code :

actions =
for structure in IDENTITE_STRUCTURE_CULTURELLE.all:
if not structure.TEST_NOMBRE_DE_LIGNES or structure.TEST_NOMBRE_DE_LIGNES < 0:
continue # Ignore les structures sans valeur définie ou négative

desired_count = int(structure.TEST_NOMBRE_DE_LIGNES)

toutes les lignes de la table ACTIONS EAC associées à cette structure
actions_eac = ACTIONS_EAC.lookupRecords(STRUCTURES_CULTURELLES=structure)

current_count = len(actions_eac)

ajouter des lignes si besoin
if desired_count > current_count:
    for _ in range(desired_count - current_count):
        actions.append([
            "AddRecord", "ACTIONS EAC", None,
            {
                "STRUCTURES CULTURELLES": structure.id
                tu peux ajouter d'autres champs ici si besoin
            }
        ])

supprimer les lignes en trop
elif desired_count < current_count:
    supprimer les dernières lignes de la liste
    à défaut d'un critère plus précis
    to_delete = [action.id for action in actions_eac[desired_count:]]
    for action_id in to_delete:
        actions.append(["RemoveRecord", "ACTIONS EAC", action_id])

return {
« button »: « Mettre à jour les actions »,
« description »: « Ajuste le nombre de lignes d’actions pour chaque structure selon la valeur cible »,
« actions »: actions
}

2- Le code semble également s’appliquer directement dans ma colonne « BOUTON ACTION » car celle-ci me renvoie :

{‹ button ›: ‹ Mettre à jour les actions ›, ‹ description ›: « Ajuste le nombre de lignes d’actions pour chaque structure selon la valeur cible », ‹ actions ›: [[‹ AddRecord ›, ‹ ACTIONS EAC ›, None, {‹ STRUCTURES CULTURELLES ›: 223}], [‹ AddRecord ›, ‹ ACTIONS EAC ›, None, {‹ STRUCTURES CULTURELLES ›: 223}], [‹ AddRecord ›, ‹ ACTIONS EAC ›, None, {‹ STRUCTURES CULTURELLES ›: 223}], [‹ AddRecord ›, ‹ ACTIONS EAC ›, None, {‹ STRUCTURES CULTURELLES ›: 223}], [‹ AddRecord ›, ‹ ACTIONS EAC ›, None, {‹ STRUCTURES CULTURELLES ›: 223}] etc…

Si jamais quelqu’un.e a une idée de ce qui génère ces réactions, ce serait d’une grande aide !
Merci d’avance :))

Célia

Super, je suis ravi que mon code serve. Rassurez-vous (ou pas), moi aussi je l’ai produit à l’aide de l’IA :sweat_smile:

Ce serait bien d’accéder au document Grist pour tester mais déjà, je vois un problème avec ACTIONS EAC : le nom de la table (ou Table ID) ne peut pas prendre d’espaces (pour avoir la Table ID, il faut regarder dans Données source).

Aussi, si vous appliquez le style « texte préformaté » (raccourci Ctrl+e) sur votre code, ça permettra de s’assurer que les guillemets sont bien des guillemets droits, que les crochets sont bien des crochets et pas un carré, que les commentaires sont bien commentés, etc.

Alors, en effet, je pense que le problème était en partie dû à cet oubli. Je suis normalement vigilante à rajouter les underscores qu’il faut, mais celui-ci est passé entre les mailles du filet. Cependant, un problème en entraînant souvent un autre :wink: le widget du bouton action m’affiche maintenant en continu « Waiting for data… ».

Je vous joins une capture d’écran et je vais continuer à chercher de mon côté. Sinon, je pourrais aussi envisager de vous partager le GRIST, mais je ne voudrais pas que ça vous prenne trop de temps.

En tout cas, merci encore pour votre aide.

Merci, je vais pouvoir investiguer plus précisément.

Mais sans attendre, je vois une erreur à la ligne for _ in range(desired_count - current_count): il faut un compteur de boucle après for (typiquement i) et il faut une borne de début et une borne de fin pour la boucle dans le range (dans mon cas count_rp_records + 1, r.Nombre_de_rapports + 1).

Bonjour,

Merci encore pour ce coup de pouce, il n’est vraiment pas de refus !
J’ai continué à investiguer de mon côté depuis hier et il y a du mieux : cette fois, le bouton d’action s’affiche bien.
Malheureusement, le script semble encore s’exécuter directement dans ma colonne « BOUTON ACTION ». Je vous joins donc le lien d’un document que j’ai créé pour simuler la même situation que celle de mon document d’origine : https://grist.numerique.gouv.fr/o/docs/jTE8pDVMAD5u/TEST-ATTRIBUTION-LIGNES?utm_id=share-doc
Si jamais vous avez un peu de temps pour y jeter un coup d’œil, ce serait vraiment d’une grande aide !

Je n’ai malheureusement pas accès au document. Mais je suis toujours motivé pour aider si je peux !

Ce que je ferais si j’étais vous :

Normalement ce diagnostic devrait nous mettre sur la piste car il semble vraiment y avoir un problème de base avec l’exécution du bouton.

On peut aussi :

  • simplifier au maximum le code pour voir ce qui bloque : essayer l’ajout de lignes seul (virer le passage entre elif et return), fixer les valeurs de desired_count et current_count (desired_count = 3 par exemple) etc.

Et, une fois que le problème de table est résolu, on peut analyser les valeurs que prennent les variables lors de l’exécution en créant une table Logs dans Grist avec une colonne Message et en remplaçant l’action par :

actions.append([
    "AddRecord", "Logs", None,
    {"Message": f"Structure {structure.id} → desired_count {desired_count} | current_count {current_count}"}
])

Re-bonjour !

Excusez moi pour ce délai de réponse, j’ai été absente cette semaine.
J’ai réessayé de vous partager le document, normalement, le lien est désormais public et en mode éditeur : https://grist.numerique.gouv.fr/o/docs/jTE8pDVMAD5u/TEST-ATTRIBUTION-LIGNES?utm_id=share-doc

Merci encore pour vos précieux conseils, je vais essayer de me saisir de tout cela et je vous ferai un retour si mes tests s’avèrent concluants.
N’hésitez pas, de votre côté, à me tenir informée si vous parvenez entre-temps à identifier l’origine du problème.

Encore merci pour votre aide, cela me ferait gagner un temps considérable si tout venait à fonctionner !

Je crois avoir débugué la formule, il fallait écrire ceci :

                {
                    "STRUCTURES_CULTURELLES": s.id,  # ID de la ligne référencée
                    "INFOS": f"Action auto {i}",
                }

car « INFOS » est une colonne alors que « Nom_action » (le précédent nom) n’est pas une colonne. D’ailleurs, vous avez beaucoup de colonnes nommées « INFOS » dans votre table, je ne sais pas si c’est voulu…

Voici l’exemple corrigé (qui fonctionne) : https://grist.numerique.gouv.fr/o/docs/8WW2p1gB3mJf/TEST-attribution-lignes?utm_id=share-doc

Est-ce que ça produit le résultat que vous attendiez ?

1 « J'aime »

Merci encore pour ton aide plus que précieuse, ça y est, cela fonctionne (presque) de mon côté aussi !

Il reste toutefois deux problématiques que je ne comprends pas très bien :

  • Lorsque j’attribue un nombre de lignes à une structure, celles-ci se créent bien dans l’autre table, mais avec le nom de la structure juste en dessous de celle à laquelle j’ai accordé ce nombre de lignes. Ci-dessous j’attribue 3 lignes à la structure ELECTRONI(K) et j’obtiens bien 3 lignes affichées, mais cette fois pour la structure ESPACE CULTUREL LACOUSTIK, qui se trouve juste en dessous d’ELECTRONI(K) dans ma liste.
    (J’ai appliqué un filtre sur ma colonne STRUCTURE afin de simplifier la lisibilité ; c’est ce qui explique que ESPACE CULTUREL LACOUSTIK et les autres n’apparaissent pas dans la colonne STRUCTURE.)

  • Deuxième comportement étrange (qu’on retrouve d’ailleurs dans votre exemple corrigé) : On ne peut pas modifier le nombre de lignes accordé. Si je reviens sur la cellule pour mettre à jour la valeur (ci-dessous j’avais initialement attribué 10 lignes à CINÉMA LE PETIT BAL PERDU, que j’ai ensuite réduites à 8), la colonne BOUTON_ACTION se met en erreur.


Les colonnes « INFOS » de mon exemple étaient plus illustratives qu’utiles : elles servaient simplement à montrer que j’avais plusieurs autres colonnes et je n’avais pas prévu de les utiliser.
C’est d’ailleurs ce qui explique le dysfonctionnement de mes précédents essais. En effet, grâce à votre modèle corrigé (merci encore !), je crois avoir compris ce qui bloquait jusque-là.

Je m’explique : mon besoin était en réalité un peu plus simple que la ressource initiale que vous proposiez. En effet, j’avais seulement besoin, à partir d’une liste de structures, de générer un nombre de lignes par structure dans une autre table, sans passer par une colonne qui comptabilise le nombre de lignes créées.
À partir du moment où, grâce à votre modèle corrigé, j’ai ajouté une colonne «INFOS » dans la table dans laquelle je voulais générer les lignes, cela a commencé à fonctionner (si on mets de côté les petits soucis détaillés au début de mon message). Je ne sais pas si mes explications sont très claires, n’hésitez pas sinon…

D’ailleurs, au choix nous pouvons continuer nos échanges sur ce fil ou peut-être passer en message direct et revenir sur celui-ci une fois la solution trouvée ?

Bonjour @Enro

Je vous remercie encore pour votre aide, qui m’a permis d’avoir une bonne base de travail.
J’ai depuis finalement trouvé, avec l’aide d’un dev, la solution correspondant à mon cas d’usage (qui, je pense, était un besoin un peu plus « simple » que le vôtre, dans le sens où j’avais seulement besoin d’une table permettant la création de lignes, sans nécessairement avoir besoin de fonctionnalités de suppression, etc.).
Je vous le mets donc ci-dessous. J’ai également ajouté une table « count » qui me permet d’afficher, par structure, le nombre de lignes existantes dans ma table.

actions = [] 

for s in IDENTITE_STRUCTURES_CULTURELLES2.all:
    if not s.TEST_NOMBRE_DE_LIGNES or s.TEST_NOMBRE_DE_LIGNES < 1:
        continue
    nb_lines_to_add = int(s.TEST_NOMBRE_DE_LIGNES)
    # Toutes les lignes ACTIONS_EAC associées à cette structure
    eac_records = ACTIONS_EAC.lookupRecords(STRUCTURES_CULTURELLES=s)

    existing_count = len(eac_records) # 0 or more

    # Ajouter des lignes si besoin

    for i in range(nb_lines_to_add):
        
        if i == nb_lines_to_add -1:
            total_nb_of_lines = existing_count + i + 1
            actions.append([
                    "AddRecord", "ACTIONS_EAC", None,
                    {
                        "STRUCTURES_CULTURELLES": s.STRUCTURE_STRUCTURE.id  # ID de la ligne référencée
                    }
                ])
        else:
            actions.append([
                    "AddRecord", "ACTIONS_EAC", None,
                    {
                        "STRUCTURES_CULTURELLES": s.STRUCTURE_STRUCTURE.id  # ID de la ligne référencée
                    }
                ])
return {
    "button": "Ajouter lignes action EAC",
    "description": "Ajoute le nombre de lignes indiqué dans TEST_NOMBRE_DE_LIGNES",
    "actions": actions
}

Désolé de n’avoir pas pris le temps de regarder votre précédent message, je suis content que vous ayez trouvé la solution !