Frappe Framework
Contrôleurs
Un contrôleur est la classe Python d’un DocType, héritée de frappe.model.Document. Cette page décrit ses méthodes, les hooks de cycle de vie, l’objet doc et les annotations de types.
Qu’est-ce qu’un contrôleur
Un contrôleur (Controller) est une classe Python ordinaire qui hérite de la classe de base frappe.model.Document. Cette classe de base porte la logique centrale d’un DocType : elle gère le chargement des valeurs depuis la base de données, leur interprétation et leur enregistrement.
Lorsque vous créez un DocType nommé Person, un fichier Python person.py est créé avec ce contenu :
import frappe
from frappe.model.document import Document
class Person(Document):
passTous les champs du DocType sont accessibles comme attributs de la classe.
Méthodes de contrôleur
Vous pouvez ajouter vos propres méthodes au contrôleur ; elles sont ensuite appelables sur l’objet doc. Par exemple :
# controller class
class Person(Document):
def get_full_name(self):
"""Returns the person's full name"""
return f"{self.first_name} {self.last_name}"
# somewhere in your code
>>> doc = frappe.get_doc("Person", "000001")
>>> doc.get_full_name()
John DoeHooks de contrôleur
Pour ajouter un comportement personnalisé au cours du cycle de vie d’un document, Frappe fournit des hooks de contrôleur (Controller Hooks). Le tableau indique, pour chaque hook, les opérations qui le déclenchent.
| Méthode | Description | Insert | Save | Submit | Cancel | Update after submit |
|---|---|---|---|---|---|---|
before_insert | Appelée avant la préparation du document pour insertion. | X | ||||
before_naming | Appelée avant que la propriété name du document soit définie. | X | ||||
autoname | Si elle est définie dans le contrôleur, cette méthode sert à définir la propriété name du document. | X | ||||
before_validate | Appelée avant la validation ; à utiliser pour renseigner automatiquement les valeurs manquantes. | X | X | X | ||
validate | Sert à lever des erreurs de validation et empêcher l’enregistrement du document. | X | X | X | ||
before_save | Appelée avant l’enregistrement du document. | X | X | |||
before_submit | Appelée avant la soumission du document. | X | X | |||
before_cancel | Appelée avant l’annulation du document. | X | ||||
before_update_after_submit | Appelée lorsque des champs d’un document soumis sont mis à jour. | X | ||||
db_insert | Insère le document en base de données ; ne la surchargez pas, sauf si vous travaillez sur un DocType virtuel. | X | ||||
after_insert | Appelée après l’insertion du document en base de données. | X | ||||
db_update | Met à jour le document en base de données ; ne la surchargez pas, sauf si vous travaillez sur un DocType virtuel. | X | X | X | X | |
on_update | Appelée lorsque les valeurs d’un document existant sont mises à jour. | X | X | X | ||
on_submit | Appelée lorsqu’un document est soumis. | X | ||||
on_cancel | Appelée lorsqu’un document soumis est annulé. | X | ||||
on_update_after_submit | Appelée lorsque les valeurs d’un document soumis sont mises à jour. | X | ||||
on_change | Appelée lorsque les valeurs d’un document ont changé. Elle est aussi appelée lors d’un db_set : les opérations qu’elle effectue doivent donc être idempotentes. | X | X | X | X | X |
En plus des événements liés aux actions classiques, vous pouvez vous brancher sur d’autres actions :
| Méthode | Description |
|---|---|
before_rename | Appelée avant le renommage d’un document. |
after_rename | Appelée après le renommage d’un document. |
on_trash | Appelée lors de la suppression d’un document. |
after_delete | Appelée après la suppression d’un document. |
Pour utiliser un hook de contrôleur, définissez simplement une méthode de classe portant ce nom. Par exemple :
class Person(Document):
def validate(self):
if self.age <= 18:
frappe.throw("Person's age must be at least 18")
def after_insert(self):
frappe.sendmail(recipients=[self.email], message="Thank you for registering!")Si les hooks ne suffisent pas, vous pouvez aussi surcharger les méthodes prédéfinies du document pour y ajouter votre propre comportement. Par exemple, pour surcharger la méthode save() :
class Person(Document):
def save(self, *args, **kwargs):
super().save(*args, **kwargs) # call the base save method
do_something() # eg: trigger an API call or a Rotating File Logger that "User X has tried updating this particular record"L’objet doc offre par défaut de nombreuses méthodes. La liste complète figure dans la page API Document.
1. Créer un document
Pour créer un nouveau document et l’enregistrer en base de données :
doc = frappe.get_doc({
'doctype': 'Person',
'first_name': 'John',
'last_name': 'Doe'
})
doc.insert()
doc.name # 0000012. Charger un document
Pour récupérer un document existant depuis la base de données :
doc = frappe.get_doc('Person', '000001')
# doctype fields
doc.first_name # John
doc.last_name # Doe
# standard fields
doc.creation # datetime.datetime(2018, 9, 20, 12, 39, 34, 236801)
doc.owner # [email protected]L’objet Document
Un document (Document) est une instance d’un DocType. Il correspond en général à une seule ligne de la table en base de données. Dans le code, on le désigne par doc.
Prenons un DocType ToDo avec les champs suivants :
descriptionstatuspriority
Pour interroger un document en base de données, on utilise l’ORM :
>>> doc = frappe.get_doc("ToDo", "0000001")
<todo: 0000001="">
>>> doc.as_dict()
{'name': '0000001',
'owner': 'Administrator',
'creation': datetime.datetime(2022, 3, 28, 18, 20, 23, 275229),
'modified': datetime.datetime(2022, 3, 28, 18, 20, 23, 275229),
'modified_by': 'Administrator',
'docstatus': 0,
'idx': 0,
'status': 'Open',
'priority': 'Medium',
'color': None,
'date': None,
'allocated_to': None,
'description': 'Test',
'reference_type': None,
'reference_name': None,
'role': None,
'assigned_by': 'Administrator',
'assigned_by_full_name': 'Administrator',
'sender': None,
'assignment_rule': None,
'doctype': 'ToDo'}Vous obtenez les valeurs de description, status et priority, mais aussi des champs comme creation, owner et modified_by, que le framework ajoute par défaut à tous les documents.
Annotations de types
> [!NOTE] > Fonctionnalité introduite dans la version 15.
Frappe peut générer automatiquement des annotations de types Python dans les fichiers de contrôleur. Ces annotations servent à l’autocomplétion, à la navigation et à la vérification de types dans le fichier du contrôleur.
class Person(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
first_name: DF.Data
last_name: DF.Data
user: DF.Link
# end: auto-generated types
pass> [!NOTE] > Ces annotations sont générées à la création ou à la mise à jour des DocTypes. Si vous modifiez ce bloc de code, il sera écrasé à la prochaine mise à jour.
Pour activer l’export automatique dans votre app, ajoutez le hook suivant :
# hooks.py
export_python_type_annotations = TruePour en savoir plus sur les annotations de types :
- Documentation du module
typingde Python - Les utilisateurs de VS Code peuvent installer l’extension Python pour une meilleure autocomplétion : https://code.visualstudio.com/docs/languages/python
- La plupart des autres éditeurs disposent d’un système de plugins équivalent basé sur LSP.
Pages liées
- API Document : liste complète des méthodes de
doc. - Nommage des documents : la méthode
autoname. - DocTypes virtuels : surcharge de
db_insertetdb_update. - Exécuter du code sur les événements d’un DocType
