Custom App

Champs additionels

En plus de vos propres DocTypes, il est possible de créer des champs personnalisés via une application personnalisée, pour simplifier la maintenance, synchroniser plusieurs sites (dev, test, préprod, prod, …), le tout sans utiliser l'interface graphique de personnalisation.

Créer des champs additionnels à l'aide d'une application personnalisée

En plus de vos propres DocTypes, il est possible de créer des champs personnalisés via une application personnalisée, pour simplifier la maintenance, synchroniser plusieurs sites (dev, test, préprod, prod, …), le tout sans utiliser l'interface graphique de personnalisation.

my_app/hooks.py
after_install = "my_app.install.after_install"
after_migrate = "my_app.install.after_migrate"
my_app/install.py
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields

# The existing OLD_FIELDS will always be deleted first.
# Make sure to include all fields that you create in this list.
# When removing a field from the CUSTOM_FIELDS list, keep its entry in the OLD_FIELDS.
# This will ensure that future migrations will correctly remove obsolete fields.
# The fields will be created in module MODULE.
# System generated property setters are always removed before migrate.
# Make sure to keep them in the PROPERTY_SETTERS list until they become obsolete.

MODULE = "My App"

OLD_FIELDS = [
    ("Customer", "my_field"),
]

CUSTOM_FIELDS = {
    "Customer": [
        {
            "fieldname": "my_app_field",
            "label": "My Field",
            "fieldtype": "Data",
            "insert_after": "customer_name",
        },
    ],
}

PROPERTY_SETTERS = [
    # {
    #   "name": "DOCTYPE-FIELD-PROPERTY",
    #   "doc_type": "DOCTYPE",
    #   "doctype_or_field": "DocField",
    #   "field_name": "FIELD",
    #   "property": "PROPERTY",
    #   "value": "VALUE",
    # },
]


def after_install():
    after_migrate()


def after_migrate():
    for dt, fieldname in OLD_FIELDS:
        if name := frappe.db.exists("Custom Field", {"dt": dt, "fieldname": fieldname}):
            frappe.delete_doc("Custom Field", name)

    # Add `module` property and `insert_after` if missing
    for fields in CUSTOM_FIELDS.values():
        prev_field = None
        for field in fields:
            field["module"] = MODULE
            if prev_field and not field.get("insert_after"):
                field["insert_after"] = prev_field["fieldname"]
            prev_field = field

    create_custom_fields(CUSTOM_FIELDS)

    # Insert property setters
    for ps in PROPERTY_SETTERS:
        assert ps["name"], "Property Setter name is required"
        frappe.delete_doc_if_exists("Property Setter", ps["name"])

        doc = frappe.new_doc("Property Setter")  # type: ignore
        doc.is_system_generated = True
        doc.module = MODULE
        doc.update(ps)
        doc.insert()

CC-BY-SA 3.0