Développement

API Controller.docs — Accès statique aux documents

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.

API Controller.docs — Accès statique aux documents

Cette API sera disponible à partir de Dodock v6 (branche develop). Elle n'est pas disponible sur la branche v5.

Lors du développement d'une application sur Dodock, vous avez toujours pu récupérer ou créer des documents via les fonctions génériques frappe.get_doc, frappe.new_doc, etc.
Dodock introduit désormais une alternative typée et statique : la collection Controller.docs, accessible directement depuis la classe Python d'un Doctype.

Cette approche présente plusieurs avantages pour les développeurs :

  • Les IDE et les analyseurs de code (Pyright, PyCharm…) comprennent le type de retour sans configuration supplémentaire.
  • 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.
  • Les imports explicites documentent les dépendances entre modules.

Prérequis

La classe controller du Doctype doit déclarer son nom de Doctype via l'attribut _DOCTYPE_NAME :

from frappe.model.document import Document

class ToDo(Document):
    _DOCTYPE_NAME = "ToDo"

Cet attribut est automatiquement présent sur les controllers générés par Dodock à partir de cette version.

Tableau de correspondance des méthodes

Ancienne API (toujours disponible)Nouvelle API Controller.docsDescription
frappe.get_doc("ToDo", "T-001")ToDo.docs.get("T-001")Récupérer un document par son nom
frappe.get_last_doc("ToDo")ToDo.docs.last()Récupérer le dernier document
frappe.get_doc("ToDo", {"reference_doc": "ABC"})ToDo.docs.last({"reference_doc": "ABC"})Récupérer un document par filtre
frappe.get_docs("ToDo", {"status": "Open"})ToDo.docs.filter({"status": "Open"})Récupérer plusieurs documents
frappe.new_doc("ToDo", {"status": "Open"})ToDo.docs.new(status="Open")Créer un nouveau document
frappe.get_cached_doc("ToDo", "T-001")ToDo.docs.get("T-001", cached=True)Récupérer depuis le cache Redis
frappe.get_lazy_doc("ToDo", "T-001")ToDo.docs.get("T-001", lazy=True)Récupérer en mode lazy
frappe.delete_doc("ToDo", "T-001")ToDo.docs.get("T-001").delete()Supprimer un document
frappe.rename_doc("ToDo", "T-001", "T-002")ToDo.docs.get("T-001").rename("T-002")Renommer un document

::: L'ancienne API (frappe.get_doc, frappe.new_doc, etc.) reste entièrement disponible et recommandée lorsque le Doctype est dynamique (inconnu à l'avance au moment de l'écriture du code). :::

Exemples d'utilisation

Récupérer un document par son nom

from frappe.desk.doctype.todo.todo import ToDo

todo = ToDo.docs.get("T-001")
print(todo.description)

Créer un nouveau document

from frappe.desk.doctype.todo.todo import ToDo

nouvel_element = ToDo.docs.new(
    description="Relancer Maison Verte SARL",
    status="Open",
    assigned_by="administrateur@example.com",
)
nouvel_element.insert()

Filtrer plusieurs documents

from frappe.desk.doctype.todo.todo import ToDo

todos_ouverts = ToDo.docs.filter({"status": "Open"})
for todo in todos_ouverts:
    print(todo.name, todo.description)

Récupérer le dernier document créé

from frappe.desk.doctype.todo.todo import ToDo

dernier_todo = ToDo.docs.last()
print(dernier_todo.name)

Récupérer un document depuis le cache Redis

Utile pour les lectures fréquentes sans modification :

from frappe.desk.doctype.todo.todo import ToDo

todo_cache = ToDo.docs.get("T-001", cached=True)

Renommer un document

from frappe.desk.doctype.todo.todo import ToDo

ToDo.docs.get("T-001").rename("T-002")

Supprimer un document

from frappe.desk.doctype.todo.todo import ToDo

ToDo.docs.get("T-001").delete()

Raccourcir les chemins d'import

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 __init__.py du dossier doctype :

# monapp/monmodule/doctype/__init__.py
from .mon_doctype.mon_doctype import MonDoctype

Ce qui permet d'écrire :

from monapp.monmodule.doctype import MonDoctype

::: Cette convention est optionnelle. Évaluez son intérêt selon la taille de votre module pour éviter les conflits de noms de symboles. :::

Déclarer _DOCTYPE_NAME sur votre controller

Pour que Controller.docs fonctionne, chaque classe doit déclarer _DOCTYPE_NAME. Sur les Doctypes existants, ajoutez simplement l'attribut de classe :

from frappe.model.document import Document

class CommandeClient(Document):
    _DOCTYPE_NAME = "Commande Client"

Sans cet attribut, l'accès à .docs lèvera une erreur explicite au moment de l'exécution.

Quand utiliser l'ancienne API ?

L'ancienne API reste la bonne solution dans les cas suivants :

  • Le nom du Doctype est déterminé dynamiquement (ex. : reçu en paramètre d'une fonction générique).
  • Vous écrivez du code partagé entre plusieurs Doctypes sans import spécifique.
  • Vous travaillez sur des scripts Dodock ou des Server Scripts où les imports Python ne sont pas disponibles.