[{"data":1,"prerenderedAt":694},["ShallowReactive",2],{"\u002Fnext\u002Fdodock\u002Fdeveloppeurs\u002Fapi\u002Fcontrollers-docs-api":3,"section:\u002Fnext\u002Fdodock\u002Fdeveloppeurs\u002Fapi\u002Fcontrollers-docs-api":693},{"id":4,"title":5,"body":6,"description":681,"extension":682,"meta":683,"navigation":101,"path":689,"seo":690,"stem":691,"__hash__":692},"docs\u002F2.next\u002F3.dodock\u002F10.developpeurs\u002F1.api\u002Fcontrollers-docs-api.md","API Controller.docs — Accès statique aux documents",{"type":7,"value":8,"toc":664},"minimark",[9,19,32,51,54,67,72,79,115,118,122,282,322,329,333,337,361,365,412,416,444,448,471,475,478,496,499,517,520,538,542,552,567,570,579,582,589,598,621,638,642,645,656,660],[10,11,13,14,18],"h1",{"id":12},"api-controllerdocs-accès-statique-aux-documents","API ",[15,16,17],"code",{},"Controller.docs"," — Accès statique aux documents",[20,21,24],"callout",{"color":22,"icon":23},"blue","i-heroicons-information-circle",[25,26,27,28,31],"p",{},"Cette API existe dans la version next de Dodock (branche ",[15,29,30],{},"develop","). Elle n'existe pas en v5.",[25,33,34,35,38,39,42,43,46,47,50],{},"Les fonctions ",[15,36,37],{},"frappe.get_doc",", ",[15,40,41],{},"frappe.new_doc"," et les autres reçoivent le nom du type de document en texte. La collection ",[15,44,45],{},"docs"," de la classe contrôleur fait le même travail à partir de la classe elle-même, par exemple ",[15,48,49],{},"ToDo.docs.get(...)",".",[25,52,53],{},"Avantages :",[55,56,57,61,64],"ul",{},[58,59,60],"li",{},"Les IDE et les analyseurs de code (Pyright, PyCharm…) comprennent le type de retour sans configuration supplémentaire.",[58,62,63],{},"Le nom du Doctype n'est plus passé en tant que chaîne de caractères : les fautes de frappe sont détectées à l'analyse statique.",[58,65,66],{},"Les imports explicites documentent les dépendances entre modules.",[68,69,71],"h2",{"id":70},"prérequis","Prérequis",[25,73,74,75,78],{},"La classe controller du Doctype doit déclarer son nom de Doctype via l'attribut ",[15,76,77],{},"_DOCTYPE_NAME"," :",[80,81,86],"pre",{"className":82,"code":83,"language":84,"meta":85,"style":85},"language-python shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","from frappe.model.document import Document\n\nclass ToDo(Document):\n    _DOCTYPE_NAME = \"ToDo\"\n","python","",[15,87,88,96,103,109],{"__ignoreMap":85},[89,90,93],"span",{"class":91,"line":92},"line",1,[89,94,95],{},"from frappe.model.document import Document\n",[89,97,99],{"class":91,"line":98},2,[89,100,102],{"emptyLinePlaceholder":101},true,"\n",[89,104,106],{"class":91,"line":105},3,[89,107,108],{},"class ToDo(Document):\n",[89,110,112],{"class":91,"line":111},4,[89,113,114],{},"    _DOCTYPE_NAME = \"ToDo\"\n",[25,116,117],{},"Dodock ajoute cet attribut aux contrôleurs qu'il génère pour un nouveau type de document.",[68,119,121],{"id":120},"tableau-de-correspondance-des-méthodes","Tableau de correspondance des méthodes",[123,124,125,143],"table",{},[126,127,128],"thead",{},[129,130,131,135,140],"tr",{},[132,133,134],"th",{},"Ancienne API (toujours disponible)",[132,136,137,138],{},"Nouvelle API ",[15,139,17],{},[132,141,142],{},"Description",[144,145,146,162,177,192,207,222,237,252,267],"tbody",{},[129,147,148,154,159],{},[149,150,151],"td",{},[15,152,153],{},"frappe.get_doc(\"ToDo\", \"T-001\")",[149,155,156],{},[15,157,158],{},"ToDo.docs.get(\"T-001\")",[149,160,161],{},"Récupérer un document par son nom",[129,163,164,169,174],{},[149,165,166],{},[15,167,168],{},"frappe.get_last_doc(\"ToDo\")",[149,170,171],{},[15,172,173],{},"ToDo.docs.last()",[149,175,176],{},"Récupérer le dernier document",[129,178,179,184,189],{},[149,180,181],{},[15,182,183],{},"frappe.get_last_doc(\"ToDo\", filters={\"reference_name\": \"ABC\"})",[149,185,186],{},[15,187,188],{},"ToDo.docs.last({\"reference_name\": \"ABC\"})",[149,190,191],{},"Récupérer le dernier document qui correspond à un filtre",[129,193,194,199,204],{},[149,195,196],{},[15,197,198],{},"frappe.get_docs(\"ToDo\", {\"status\": \"Open\"})",[149,200,201],{},[15,202,203],{},"ToDo.docs.filter({\"status\": \"Open\"})",[149,205,206],{},"Récupérer plusieurs documents",[129,208,209,214,219],{},[149,210,211],{},[15,212,213],{},"frappe.new_doc(\"ToDo\", status=\"Open\")",[149,215,216],{},[15,217,218],{},"ToDo.docs.new(status=\"Open\")",[149,220,221],{},"Créer un nouveau document (non enregistré)",[129,223,224,229,234],{},[149,225,226],{},[15,227,228],{},"frappe.get_cached_doc(\"ToDo\", \"T-001\")",[149,230,231],{},[15,232,233],{},"ToDo.docs.get(\"T-001\", cached=True)",[149,235,236],{},"Récupérer depuis le cache",[129,238,239,244,249],{},[149,240,241],{},[15,242,243],{},"frappe.get_lazy_doc(\"ToDo\", \"T-001\")",[149,245,246],{},[15,247,248],{},"ToDo.docs.get(\"T-001\", lazy=True)",[149,250,251],{},"Récupérer en mode lazy",[129,253,254,259,264],{},[149,255,256],{},[15,257,258],{},"frappe.delete_doc(\"ToDo\", \"T-001\")",[149,260,261],{},[15,262,263],{},"ToDo.docs.get(\"T-001\").delete()",[149,265,266],{},"Supprimer un document",[129,268,269,274,279],{},[149,270,271],{},[15,272,273],{},"frappe.rename_doc(\"ToDo\", \"T-001\", \"T-002\")",[149,275,276],{},[15,277,278],{},"ToDo.docs.get(\"T-001\").rename(\"T-002\")",[149,280,281],{},"Renommer un document",[25,283,284,287,288,291,292,295,296,299,300,38,303,306,307,310,311,314,315,306,318,321],{},[15,285,286],{},"docs.get()"," accepte aussi ",[15,289,290],{},"for_update=True"," (verrouille la ligne) et ",[15,293,294],{},"check_permission=\"read\""," (contrôle l'autorisation). ",[15,297,298],{},"docs.filter()"," accepte ",[15,301,302],{},"limit",[15,304,305],{},"order_by"," et ",[15,308,309],{},"as_iterator=True"," (lecture par lots de ",[15,312,313],{},"chunk_size"," documents). ",[15,316,317],{},"cached",[15,319,320],{},"lazy"," ne se combinent pas.",[20,323,326],{"color":324,"icon":325},"teal","i-heroicons-light-bulb",[25,327,328],{},"L'ancienne API reste disponible. Utilisez-la quand le type de document n'est connu qu'à l'exécution.",[68,330,332],{"id":331},"exemples-dutilisation","Exemples d'utilisation",[334,335,161],"h3",{"id":336},"récupérer-un-document-par-son-nom",[80,338,340],{"className":82,"code":339,"language":84,"meta":85,"style":85},"from frappe.desk.doctype.todo.todo import ToDo\n\ntodo = ToDo.docs.get(\"T-001\")\nprint(todo.description)\n",[15,341,342,347,351,356],{"__ignoreMap":85},[89,343,344],{"class":91,"line":92},[89,345,346],{},"from frappe.desk.doctype.todo.todo import ToDo\n",[89,348,349],{"class":91,"line":98},[89,350,102],{"emptyLinePlaceholder":101},[89,352,353],{"class":91,"line":105},[89,354,355],{},"todo = ToDo.docs.get(\"T-001\")\n",[89,357,358],{"class":91,"line":111},[89,359,360],{},"print(todo.description)\n",[334,362,364],{"id":363},"créer-un-nouveau-document","Créer un nouveau document",[80,366,368],{"className":82,"code":367,"language":84,"meta":85,"style":85},"from frappe.desk.doctype.todo.todo import ToDo\n\nnouvel_element = ToDo.docs.new(\n    description=\"Relancer Maison Verte SARL\",  # client fictif\n    status=\"Open\",\n    assigned_by=\"administrateur@example.com\",\n)\nnouvel_element.insert()\n",[15,369,370,374,378,383,388,394,400,406],{"__ignoreMap":85},[89,371,372],{"class":91,"line":92},[89,373,346],{},[89,375,376],{"class":91,"line":98},[89,377,102],{"emptyLinePlaceholder":101},[89,379,380],{"class":91,"line":105},[89,381,382],{},"nouvel_element = ToDo.docs.new(\n",[89,384,385],{"class":91,"line":111},[89,386,387],{},"    description=\"Relancer Maison Verte SARL\",  # client fictif\n",[89,389,391],{"class":91,"line":390},5,[89,392,393],{},"    status=\"Open\",\n",[89,395,397],{"class":91,"line":396},6,[89,398,399],{},"    assigned_by=\"administrateur@example.com\",\n",[89,401,403],{"class":91,"line":402},7,[89,404,405],{},")\n",[89,407,409],{"class":91,"line":408},8,[89,410,411],{},"nouvel_element.insert()\n",[334,413,415],{"id":414},"filtrer-plusieurs-documents","Filtrer plusieurs documents",[80,417,419],{"className":82,"code":418,"language":84,"meta":85,"style":85},"from frappe.desk.doctype.todo.todo import ToDo\n\ntodos_ouverts = ToDo.docs.filter({\"status\": \"Open\"})\nfor todo in todos_ouverts:\n    print(todo.name, todo.description)\n",[15,420,421,425,429,434,439],{"__ignoreMap":85},[89,422,423],{"class":91,"line":92},[89,424,346],{},[89,426,427],{"class":91,"line":98},[89,428,102],{"emptyLinePlaceholder":101},[89,430,431],{"class":91,"line":105},[89,432,433],{},"todos_ouverts = ToDo.docs.filter({\"status\": \"Open\"})\n",[89,435,436],{"class":91,"line":111},[89,437,438],{},"for todo in todos_ouverts:\n",[89,440,441],{"class":91,"line":390},[89,442,443],{},"    print(todo.name, todo.description)\n",[334,445,447],{"id":446},"récupérer-le-dernier-document-créé","Récupérer le dernier document créé",[80,449,451],{"className":82,"code":450,"language":84,"meta":85,"style":85},"from frappe.desk.doctype.todo.todo import ToDo\n\ndernier_todo = ToDo.docs.last()\nprint(dernier_todo.name)\n",[15,452,453,457,461,466],{"__ignoreMap":85},[89,454,455],{"class":91,"line":92},[89,456,346],{},[89,458,459],{"class":91,"line":98},[89,460,102],{"emptyLinePlaceholder":101},[89,462,463],{"class":91,"line":105},[89,464,465],{},"dernier_todo = ToDo.docs.last()\n",[89,467,468],{"class":91,"line":111},[89,469,470],{},"print(dernier_todo.name)\n",[334,472,474],{"id":473},"récupérer-un-document-depuis-le-cache","Récupérer un document depuis le cache",[25,476,477],{},"Pour des lectures fréquentes, sans modification du document :",[80,479,481],{"className":82,"code":480,"language":84,"meta":85,"style":85},"from frappe.desk.doctype.todo.todo import ToDo\n\ntodo_cache = ToDo.docs.get(\"T-001\", cached=True)\n",[15,482,483,487,491],{"__ignoreMap":85},[89,484,485],{"class":91,"line":92},[89,486,346],{},[89,488,489],{"class":91,"line":98},[89,490,102],{"emptyLinePlaceholder":101},[89,492,493],{"class":91,"line":105},[89,494,495],{},"todo_cache = ToDo.docs.get(\"T-001\", cached=True)\n",[334,497,281],{"id":498},"renommer-un-document",[80,500,502],{"className":82,"code":501,"language":84,"meta":85,"style":85},"from frappe.desk.doctype.todo.todo import ToDo\n\nToDo.docs.get(\"T-001\").rename(\"T-002\")\n",[15,503,504,508,512],{"__ignoreMap":85},[89,505,506],{"class":91,"line":92},[89,507,346],{},[89,509,510],{"class":91,"line":98},[89,511,102],{"emptyLinePlaceholder":101},[89,513,514],{"class":91,"line":105},[89,515,516],{},"ToDo.docs.get(\"T-001\").rename(\"T-002\")\n",[334,518,266],{"id":519},"supprimer-un-document",[80,521,523],{"className":82,"code":522,"language":84,"meta":85,"style":85},"from frappe.desk.doctype.todo.todo import ToDo\n\nToDo.docs.get(\"T-001\").delete()\n",[15,524,525,529,533],{"__ignoreMap":85},[89,526,527],{"class":91,"line":92},[89,528,346],{},[89,530,531],{"class":91,"line":98},[89,532,102],{"emptyLinePlaceholder":101},[89,534,535],{"class":91,"line":105},[89,536,537],{},"ToDo.docs.get(\"T-001\").delete()\n",[68,539,541],{"id":540},"raccourcir-les-chemins-dimport","Raccourcir les chemins d'import",[25,543,544,545,548,549,78],{},"Les chemins d'import vers les controllers peuvent être longs. Pour les modules comportant de nombreux Doctypes, vous pouvez exposer les classes dans le fichier ",[15,546,547],{},"__init__.py"," du dossier ",[15,550,551],{},"doctype",[80,553,555],{"className":82,"code":554,"language":84,"meta":85,"style":85},"# monapp\u002Fmonmodule\u002Fdoctype\u002F__init__.py\nfrom .mon_doctype.mon_doctype import MonDoctype\n",[15,556,557,562],{"__ignoreMap":85},[89,558,559],{"class":91,"line":92},[89,560,561],{},"# monapp\u002Fmonmodule\u002Fdoctype\u002F__init__.py\n",[89,563,564],{"class":91,"line":98},[89,565,566],{},"from .mon_doctype.mon_doctype import MonDoctype\n",[25,568,569],{},"Ce qui permet d'écrire :",[80,571,573],{"className":82,"code":572,"language":84,"meta":85,"style":85},"from monapp.monmodule.doctype import MonDoctype\n",[15,574,575],{"__ignoreMap":85},[89,576,577],{"class":91,"line":92},[89,578,572],{},[25,580,581],{},"Cette convention est facultative. Dans un gros module, elle peut créer des conflits de noms.",[68,583,585,586,588],{"id":584},"déclarer-_doctype_name-sur-votre-controller","Déclarer ",[15,587,77],{}," sur votre controller",[25,590,591,592,594,595,597],{},"Pour que ",[15,593,17],{}," fonctionne, chaque classe doit déclarer ",[15,596,77],{},". Sur les Doctypes existants, ajoutez simplement l'attribut de classe :",[80,599,601],{"className":82,"code":600,"language":84,"meta":85,"style":85},"from frappe.model.document import Document\n\nclass DemandeIntervention(Document):  # type de document fictif\n    _DOCTYPE_NAME = \"Demande Intervention\"\n",[15,602,603,607,611,616],{"__ignoreMap":85},[89,604,605],{"class":91,"line":92},[89,606,95],{},[89,608,609],{"class":91,"line":98},[89,610,102],{"emptyLinePlaceholder":101},[89,612,613],{"class":91,"line":105},[89,614,615],{},"class DemandeIntervention(Document):  # type de document fictif\n",[89,617,618],{"class":91,"line":111},[89,619,620],{},"    _DOCTYPE_NAME = \"Demande Intervention\"\n",[25,622,623,624,627,628,631,632,634,635,637],{},"Sans cet attribut, ",[15,625,626],{},".docs"," lève une erreur ",[15,629,630],{},"AttributeError"," : « … does not define ",[15,633,77],{}," ». ",[15,636,626],{}," n'est accessible que depuis la classe, pas depuis une instance.",[68,639,641],{"id":640},"quand-utiliser-lancienne-api","Quand utiliser l'ancienne API ?",[25,643,644],{},"L'ancienne API reste la bonne solution dans les cas suivants :",[55,646,647,650,653],{},[58,648,649],{},"Le nom du Doctype est déterminé dynamiquement (ex. : reçu en paramètre d'une fonction générique).",[58,651,652],{},"Vous écrivez du code partagé entre plusieurs Doctypes sans import spécifique.",[58,654,655],{},"Vous écrivez un script serveur : les imports n'y sont pas disponibles.",[657,658,659],"mermaid",{},"\nflowchart TD\n    A[Doctype connu à l'écriture du code ?] -->|Oui| B[Utiliser Controller.docs]\n    A -->|Non| C[Utiliser frappe.get_doc \u002F frappe.new_doc]\n    B --> D[Import explicite de la classe]\n    B --> E[Analyse statique + autocomplétion IDE]\n    C --> F[Chaîne de caractères dynamique]\n",[661,662,663],"style",{},"html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":85,"searchDepth":92,"depth":98,"links":665},[666,667,668,677,678,680],{"id":70,"depth":98,"text":71},{"id":120,"depth":98,"text":121},{"id":331,"depth":98,"text":332,"children":669},[670,671,672,673,674,675,676],{"id":336,"depth":105,"text":161},{"id":363,"depth":105,"text":364},{"id":414,"depth":105,"text":415},{"id":446,"depth":105,"text":447},{"id":473,"depth":105,"text":474},{"id":498,"depth":105,"text":281},{"id":519,"depth":105,"text":266},{"id":540,"depth":98,"text":541},{"id":584,"depth":98,"text":679},"Déclarer _DOCTYPE_NAME sur votre controller",{"id":640,"depth":98,"text":641},"Utilisez les collections Controller.docs pour manipuler vos documents Doctype directement depuis leur classe Python, sans passer par les fonctions génériques de frappe.","md",{"reviewed":101,"last_verified":684,"sources":685},"2026-11-03",[686,687,688],"dodock@develop:frappe\u002Fmodel\u002Fdocument.py","dodock@develop:frappe\u002Fmodules\u002Futils.py","dodock@develop:frappe\u002Fdesk\u002Fdoctype\u002Ftodo\u002Ftodo.py","\u002Fnext\u002Fdodock\u002Fdeveloppeurs\u002Fapi\u002Fcontrollers-docs-api",{"title":5,"description":681},"2.next\u002F3.dodock\u002F10.developpeurs\u002F1.api\u002Fcontrollers-docs-api","3uEvR3tY5JzYEEhAEzDVH5uwTZpBv6PaW50EY20wSu0",{},1793871728072]