Documentation Frappe Framework

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.

5 min de lectureMis à jour le Source : docs.frappe.io

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 :

python
import frappe
from frappe.model.document import Document

class Person(Document):
    pass

Tous 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 :

python
# 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 Doe

Hooks 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éthodeDescriptionInsertSaveSubmitCancelUpdate after submit
before_insertAppelée avant la préparation du document pour insertion.X
before_namingAppelée avant que la propriété name du document soit définie.X
autonameSi elle est définie dans le contrôleur, cette méthode sert à définir la propriété name du document.X
before_validateAppelée avant la validation ; à utiliser pour renseigner automatiquement les valeurs manquantes.XXX
validateSert à lever des erreurs de validation et empêcher l’enregistrement du document.XXX
before_saveAppelée avant l’enregistrement du document.XX
before_submitAppelée avant la soumission du document.XX
before_cancelAppelée avant l’annulation du document.X
before_update_after_submitAppelée lorsque des champs d’un document soumis sont mis à jour.X
db_insertInsère le document en base de données ; ne la surchargez pas, sauf si vous travaillez sur un DocType virtuel.X
after_insertAppelée après l’insertion du document en base de données.X
db_updateMet à jour le document en base de données ; ne la surchargez pas, sauf si vous travaillez sur un DocType virtuel.XXXX
on_updateAppelée lorsque les valeurs d’un document existant sont mises à jour.XXX
on_submitAppelée lorsqu’un document est soumis.X
on_cancelAppelée lorsqu’un document soumis est annulé.X
on_update_after_submitAppelée lorsque les valeurs d’un document soumis sont mises à jour.X
on_changeAppelé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.XXXXX

En plus des événements liés aux actions classiques, vous pouvez vous brancher sur d’autres actions :

MéthodeDescription
before_renameAppelée avant le renommage d’un document.
after_renameAppelée après le renommage d’un document.
on_trashAppelée lors de la suppression d’un document.
after_deleteAppelé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 :

python
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() :

python
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 :

python
doc = frappe.get_doc({
    'doctype': 'Person',
    'first_name': 'John',
    'last_name': 'Doe'
})
doc.insert()

doc.name # 000001

2. Charger un document

Pour récupérer un document existant depuis la base de données :

python
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 :

  • description
  • status
  • priority

Pour interroger un document en base de données, on utilise l’ORM :

python
>>> 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.

python
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 :

python
# hooks.py

export_python_type_annotations = True

Pour en savoir plus sur les annotations de types :

Pages liées