View on GitHub

knowledge

Fields hints

Move a field into a different fieldset

https://community.plone.org/t/moving-behavior-fields-to-different-fieldset/6219/7

from plone.supermodel.interfaces import FIELDSETS_KEY
from plone.supermodel.model import Fieldset


def move_field(
    schema, fieldname, to_fieldset_name, label=None, description=None, order=None
):
    """Moves a field named "fieldname" on a Zope "schema" to a new fieldset "to_field_name".

    - creates a new fieldset on demand (then label, description and order are passed to the new one).
    - if value of "to_fieldset_name" is "default", then the field sticks on the main form.
    """
    # find schema with field in inheritance tree
    schema_with_field = None
    for pschema in reversed(schema.__iro__):
        if pschema.direct(fieldname):
            schema_with_field = pschema
            break
    if schema_with_field is None:
        raise KeyError(f"field '{fieldname}' does not exist on {schema}.")

    # remove field from fieldset (if in any)
    fieldsets_direct = schema_with_field.queryDirectTaggedValue(FIELDSETS_KEY)
    if fieldsets_direct is not None:
        for fieldset in fieldsets_direct:
            if fieldname in fieldset.fields:
                fieldset.fields.remove(fieldname)
                break

    if to_fieldset_name == "default":
        # default means to fieldset, but on main form
        return

    if fieldsets_direct is None:
        # no tagged value set so far!
        fieldsets_direct = list()
        schema.setTaggedValue(FIELDSETS_KEY, fieldsets_direct)

    # try to find the fieldset, append and exit
    for fieldset in fieldsets_direct:
        if fieldset.__name__ == to_fieldset_name:
            fieldset.fields.append(fieldname)
            return

    # not found, need to create new fieldset
    new_fieldset = Fieldset(
        to_fieldset_name,
        fields=[fieldname],
    )
    if label is not None:
        new_fieldset.label = label
    if description is not None:
        new_fieldset.description = description
    if order is not None:
        new_fieldset.order = order
    fieldsets_direct.append(new_fieldset)
    # Done!



# example
from plone.app.contenttypes.behaviors.leadimage import ILeadImageBehavior
from plone.app.dexterity.behaviors.metadata import ICategorization
from plone.app.dexterity.behaviors.metadata import IDublinCore


# 1) move direct field language on ICategorization from fieldset
#    categorization to settings
move_field(ICategorization, "language", "settings")

# 2) move inherited field subject on IDublinCore from fieldset
#    categorization to settings
move_field(IDublinCore, "subjects", "settings")

# 3) move inherited field image on ILeadImage from main form
#    to new fiedset images
move_field(ILeadImageBehavior, "image", "images", label="Images", order=10)