Les valeurs dérivées
Un exemplaire prend le rayon de son œuvre. Une ligne de commande prend l’unité et le prix du produit. Un emprunt part de la date du jour. Trois fois la même chose : un champ qui se déduit d’un autre.
from kewos.orm.derived_defaults import DerivedDefault
registry.register_model( "library_copy", module="library", fields=[...], derived_defaults=( DerivedDefault(field="shelf", source="title_id.genre"), ),)Cinq sources, aucune ligne de code
source | Ce qu’elle vaut |
|---|---|
"@current_user" | L’utilisateur courant (un champ Link vers l’utilisateur). |
"@current_user_record:<champ>" | La fiche dont <champ> est l’utilisateur courant. La recherche inverse. |
"@today", "@current_month_start", "@current_month_end" | La date du jour, le premier ou le dernier jour du mois. |
"<champ>" | La valeur d’un champ voisin de la même fiche. |
"<relation>.<attribut>" | Un saut de relation : on charge la cible du Link et on lit son attribut. |
C’est une liste fermée, et c’est le sujet. Un champ calculé à la volée par du Python fourni par un utilisateur serait une exécution de code arbitraire (interdiction n°37). Ici, la déclaration est une chaîne, le noyau la résout, et il n’y a rien à exécuter.
À la création : remplir si vide
La dérivation tourne côté serveur, dans la session, donc quelle que soit la porte d’entrée : l’interface, l’API, un import.
POST /api/v1/library_loan {"copy_id":1,"member_id":1,"due_on":"2026-10-01"}
-> {"id":19, "taken_on":"2026-09-06", ...}taken_on n’était pas dans la demande : il vaut aujourd’hui. Et une valeur fournie n’est
jamais écrasée : la règle est « remplir si vide », pas « imposer ».
Dans le formulaire : recalculer au changement
Le pendant interactif est le recalcul. Quand l’utilisateur change un champ dont dépend une dérivation, le formulaire demande au serveur les nouvelles valeurs, avant d’enregistrer :
POST /api/v1/library_copy/recompute {"values": {"title_id": 1, "barcode": "X-1"}, "changed": "title_id"} -> {"values": {"shelf": "fiction", "name": "X-1 - fiction"}, ...}
POST /api/v1/library_copy/recompute {"values": {"title_id": 2, "barcode": "X-1"}, "changed": "title_id"} -> {"values": {"shelf": "science", "name": "X-1 - science"}, ...}Le titre 1 est un roman, le titre 2 un essai scientifique : le rayon suit. Notez que le champ
calculé name suit aussi, dans le même aller-retour. Le frontend n’a rien calculé : il a envoyé
le brouillon et fusionné la réponse.
Un champ obligatoire peut être dérivé
Un champ nullable=False avec une dérivation peut être omis de l’appel : il sera rempli
avant l’écriture. C’était faux jusqu’à cette page : la validation du corps de la requête
réclamait le champ avant que la session ait son tour, donc la promesse « quelle que soit la porte
d’entrée » ne tenait pas pour l’API. Deux modèles du produit étaient dans ce cas
(inventory_movement et ses deux emplacements, dérivés de l’opération parente).
Et si la dérivation ne trouve rien, la base refuse la ligne : le serveur répond alors 400 en nommant le champ, pas un 500 et pas une phrase sur les doublons.