Version de développement
Cette documentation décrit la version « next » (develop), non encore publiée. Pour la version stable, basculez sur « v5 » dans l'en-tête.
API

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 existe dans la version next de Dodock (branche develop). Elle n'existe pas en v5.

Les fonctions frappe.get_doc, frappe.new_doc et les autres reçoivent le nom du type de document en texte. La collection docs de la classe contrôleur fait le même travail à partir de la classe elle-même, par exemple ToDo.docs.get(...).

Avantages :

  • 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"

Dodock ajoute cet attribut aux contrôleurs qu'il génère pour un nouveau type de document.

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_last_doc("ToDo", filters={"reference_name": "ABC"})ToDo.docs.last({"reference_name": "ABC"})Récupérer le dernier document qui correspond à un 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 (non enregistré)
frappe.get_cached_doc("ToDo", "T-001")ToDo.docs.get("T-001", cached=True)Récupérer depuis le cache
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

docs.get() accepte aussi for_update=True (verrouille la ligne) et check_permission="read" (contrôle l'autorisation). docs.filter() accepte limit, order_by et as_iterator=True (lecture par lots de chunk_size documents). cached et lazy ne se combinent pas.

L'ancienne API reste disponible. Utilisez-la quand le type de document n'est connu qu'à l'exécution.

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",  # client fictif
    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

Pour des lectures fréquentes, sans modification du document :

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 facultative. Dans un gros module, elle peut créer des conflits de noms.

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 DemandeIntervention(Document):  # type de document fictif
    _DOCTYPE_NAME = "Demande Intervention"

Sans cet attribut, .docs lève une erreur AttributeError : « … does not define _DOCTYPE_NAME ». .docs n'est accessible que depuis la classe, pas depuis une instance.

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 écrivez un script serveur : les imports n'y sont pas disponibles.