Skip to content

Layout

Layout

djadmin.layout.Layout

Top-level layout definition for a form.

Part of core djadmin. Can be used with or without djadmin-formset plugin.

Examples

Simple (works without plugin)

Layout( Field('name'), Field('email'), )

With fieldsets (works without plugin)

Layout( Fieldset('Personal', Field('name'), Field('birth_date'), ), )

With collections (⚠️ requires plugin!)

Layout( Field('name'), Collection('books', model=Book, fields=['title']), )

Method Resolution Order

  1. djadmin.layout.Layout

Attributes

Attribute Value Defined in
__annotations__ {'items': <class 'tuple'>, 'renderer': type | None, 'css_... djadmin.layout.Layout
__dataclass_fields__ {'items': Field(name='items',type=<class 'tuple'>,default... djadmin.layout.Layout
__dataclass_params__ _DataclassParams(init=True,repr=True,eq=True,order=False,... djadmin.layout.Layout
__hash__ None djadmin.layout.Layout
__match_args__ ('items', 'renderer', 'css_classes') djadmin.layout.Layout
renderer None djadmin.layout.Layout

Methods

__eq__(self, other)

Defined in: <class 'djadmin.layout.Layout'>

Return self==value.

__init__(self, *items, renderer: type | None = None, css_classes: list[str] | None = None)

Defined in: <class 'djadmin.layout.Layout'>

Initialize self. See help(type(self)) for accurate signature.

Source code in layout.py line 600
    def __init__(self, *items, renderer: type | None = None, css_classes: list[str] | None = None):
        self.items = items
        self.renderer = renderer
        self.css_classes = css_classes or []

        if not items:
            raise ValueError('Layout must contain at least one item')

__repr__(self)

Defined in: <class 'djadmin.layout.Layout'>

Multi-line string representation for readability.

Source code in layout.py line 775
    def __repr__(self):
        """Multi-line string representation for readability."""
        if len(self.items) == 1:
            # Single item - keep on one line
            items_repr = repr(self.items[0])
        else:
            # Multiple items - multi-line with indentation
            items_repr = ',\n    '.join(repr(item) for item in self.items)
            items_repr = f'\n    {items_repr}\n'

        parts = [items_repr]
        if self.renderer:
            if hasattr(self.renderer, '__name__'):
                parts.append(f'renderer={self.renderer.__name__}')
            else:
                parts.append(f'renderer={self.renderer!r}')
        if self.css_classes:
            parts.append(f'css_classes={self.css_classes!r}')

        return f"Layout({', '.join(parts)})"

from_fieldsets(fieldsets) @classmethod

Defined in: <class 'djadmin.layout.Layout'>

Convert Django admin fieldsets to Layout.

Converts the Django admin fieldsets format to the Layout API: - Named fieldsets → Fieldset with legend - Unnamed fieldsets (None, {...}) → Fieldset with legend=None - Tuple syntax ('field1', 'field2') → Row(Field('field1'), Field('field2')) - 'classes' → css_classes - 'description' → description

Args: fieldsets: Django admin fieldsets tuple format

Returns: Layout instance

Example: # Django admin format fieldsets = ( ('Personal', { 'fields': ('name', ('first_name', 'last_name')) }), )

# Converts to:
Layout(
    Fieldset('Personal',
        Field('name'),
        Row(
            Field('first_name'),
            Field('last_name'),
        ),
    ),
)
Source code in layout.py line 608
    @classmethod
    def from_fieldsets(cls, fieldsets):
        """
        Convert Django admin fieldsets to Layout.

        Converts the Django admin fieldsets format to the Layout API:
        - Named fieldsets → Fieldset with legend
        - Unnamed fieldsets (None, {...}) → Fieldset with legend=None
        - Tuple syntax ('field1', 'field2') → Row(Field('field1'), Field('field2'))
        - 'classes' → css_classes
        - 'description' → description

        Args:
            fieldsets: Django admin fieldsets tuple format

        Returns:
            Layout instance

        Example:
            # Django admin format
            fieldsets = (
                ('Personal', {
                    'fields': ('name', ('first_name', 'last_name'))
                }),
            )

            # Converts to:
            Layout(
                Fieldset('Personal',
                    Field('name'),
                    Row(
                        Field('first_name'),
                        Field('last_name'),
                    ),
                ),
            )
        """
        layout_items = []

        for fieldset_def in fieldsets:
            # fieldset_def is (legend, options_dict)
            legend, options = fieldset_def

            # Get fields from options
            fields_spec = options.get('fields', ())
            description = options.get('description')
            classes = options.get('classes', [])

            # Convert fields spec to Field/Row objects
            fieldset_items = []
            for field_spec in fields_spec:
                if isinstance(field_spec, tuple):
                    # Tuple means Row
                    row_fields = [Field(name) if isinstance(name, str) else name for name in field_spec]
                    fieldset_items.append(Row(*row_fields))
                elif isinstance(field_spec, str):
                    # String means Field
                    fieldset_items.append(Field(field_spec))
                elif isinstance(field_spec, Field):
                    # Already a Field object
                    fieldset_items.append(field_spec)
                else:
                    raise ValueError(f'Unknown field spec type: {type(field_spec)}')

            # Create Fieldset
            fieldset = Fieldset(legend, *fieldset_items, description=description, css_classes=classes)
            layout_items.append(fieldset)

        return cls(*layout_items)

get_features(self) -> set

Defined in: <class 'djadmin.layout.Layout'>

Get the set of features required by this layout.

Used for feature advertising to plugins.

Returns: Set of feature names: - 'collections' / 'inlines': Layout contains Collection components - 'conditional_fields': Layout uses show_if/hide_if - 'computed_fields': Layout uses calculate

Source code in layout.py line 678
    def get_features(self) -> set:
        """
        Get the set of features required by this layout.

        Used for feature advertising to plugins.

        Returns:
            Set of feature names:
            - 'collections' / 'inlines': Layout contains Collection components
            - 'conditional_fields': Layout uses show_if/hide_if
            - 'computed_fields': Layout uses calculate
        """
        features = set()

        def check_item(item):
            if isinstance(item, Collection):
                features.add('collections')
                features.add('inlines')  # Alias
                # Recursively check nested layout
                if item.layout:
                    features.update(item.layout.get_features())

            elif isinstance(item, Field):
                if item.show_if or item.hide_if:
                    features.add('conditional_fields')
                if item.calculate:
                    features.add('computed_fields')

            elif isinstance(item, Fieldset | Row):
                for field in item.fields:
                    check_item(field)

            elif isinstance(item, Layout):
                for i in item.items:
                    check_item(i)

        for item in self.items:
            check_item(item)

        return features

get_field_names(self) -> list[str]

Defined in: <class 'djadmin.layout.Layout'>

Recursively extract all field names from layout.

Used to provide Django's ModelForm with the fields list when only a layout is specified (no explicit fields attribute).

Returns: List of field names (strings) for use with Django's ModelForm fields attribute. Collections are excluded as they represent inline editing, not top-level fields.

Example: >>> layout = Layout( ... Field('name'), ... Fieldset('Details', ... Field('price'), ... Row(Field('sku'), Field('category')), ... ), ... ) >>> layout.get_field_names() ['name', 'price', 'sku', 'category']

Source code in layout.py line 719
    def get_field_names(self) -> list[str]:
        """
        Recursively extract all field names from layout.

        Used to provide Django's ModelForm with the fields list when only
        a layout is specified (no explicit fields attribute).

        Returns:
            List of field names (strings) for use with Django's ModelForm fields attribute.
            Collections are excluded as they represent inline editing, not top-level fields.

        Example:
            >>> layout = Layout(
            ...     Field('name'),
            ...     Fieldset('Details',
            ...         Field('price'),
            ...         Row(Field('sku'), Field('category')),
            ...     ),
            ... )
            >>> layout.get_field_names()
            ['name', 'price', 'sku', 'category']
        """

        def _extract_from_items(items):
            """Recursively extract field names from a collection of items."""
            field_names = []
            for item in items:
                if isinstance(item, Field):
                    field_names.append(item.name)
                elif isinstance(item, Fieldset | Row):
                    field_names.extend(_extract_from_items(item.fields))
                elif isinstance(item, Collection):
                    # Collections are inlines, not top-level fields
                    pass
                elif isinstance(item, Layout):
                    field_names.extend(_extract_from_items(item.items))
            return field_names

        return _extract_from_items(self.items)

render_for_display(self, obj) -> list

Defined in: <class 'djadmin.layout.Layout'>

Render layout for display (top-level).

Args: obj: Model instance to get field values from

Returns: List of rendered layout items (each is a dict)

Source code in layout.py line 759
    def render_for_display(self, obj) -> list:
        """
        Render layout for display (top-level).

        Args:
            obj: Model instance to get field values from

        Returns:
            List of rendered layout items (each is a dict)
        """
        items = []
        for item in self.items:
            items.append(item.render_for_display(obj))

        return items

Fields

Field Type Related To
__dict__ getset_descriptor -
__weakref__ getset_descriptor -