Skip to content

Collection

Collection

djadmin.layout.Collection

A collection of related objects (inline editing).

⚠️ Requires djadmin-formset plugin to work! Without plugin: Will trigger feature advertisement and show helpful error.

Examples

Simple

Collection('books', model=Book, fields=['title', 'isbn'])

With layout

Collection('books', model=Book, layout=Layout( Field('title'), Row( Field('isbn', css_classes=['flex-1']), Field('format', css_classes=['flex-1']), ), ), is_sortable=True, )

Nested collections

Collection('addresses', model=Address, layout=Layout( Field('street'), Collection('contacts', # Nested! model=Contact, fields=['phone', 'email'] ) ) )

Display styles (Django admin compatibility)

Collection('orderitem_set', model=OrderItem, fields=['product', 'quantity', 'price'], display_style='tabular', # Compact table layout (default) )

Collection('shipping_addresses', model=ShippingAddress, fields=['street', 'city', 'state', 'zip_code'], display_style='stacked', # Vertical form layout )

Method Resolution Order

  1. djadmin.layout.Collection

Attributes

Attribute Value Defined in
__annotations__ {'name': <class 'str'>, 'model': type[django.db.models.ba... djadmin.layout.Collection
__dataclass_fields__ {'name': Field(name='name',type=<class 'str'>,default=<da... djadmin.layout.Collection
__dataclass_params__ _DataclassParams(init=True,repr=True,eq=True,order=False,... djadmin.layout.Collection
__hash__ None djadmin.layout.Collection
__match_args__ ('name', 'model', 'fields', 'layout', 'min_siblings', 'ma... djadmin.layout.Collection
display_style tabular djadmin.layout.Collection
extra_siblings 1 djadmin.layout.Collection
fields None djadmin.layout.Collection
form_class None djadmin.layout.Collection
is_sortable False djadmin.layout.Collection
layout None djadmin.layout.Collection
legend None djadmin.layout.Collection
max_siblings 1000 djadmin.layout.Collection
min_siblings 0 djadmin.layout.Collection

Methods

__eq__(self, other)

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

Return self==value.

__init__(self, name: str, model: type[django.db.models.base.Model], fields: list[typing.Union[str, ForwardRef('Field')]] | None = None, layout: Optional[ForwardRef('Layout')] = None, min_siblings: int = 0, max_siblings: int = 1000, extra_siblings: int = 1, is_sortable: bool = False, legend: str | None = None, display_style: str = 'tabular', form_class: type | None = None) -> None

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

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

__post_init__(self)

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

Validation.

Source code in layout.py line 332
    def __post_init__(self):
        """Validation."""
        if self.fields and self.layout:
            raise ValueError(f"Collection '{self.name}' cannot specify both fields and layout")
        if not self.fields and not self.layout:
            raise ValueError(f"Collection '{self.name}' must specify either fields or layout")

        # Validate display_style
        if self.display_style not in ('tabular', 'stacked'):
            raise ValueError(f"display_style must be 'tabular' or 'stacked', got {self.display_style!r}")

__repr__(self)

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

String representation with non-default values.

Source code in layout.py line 343
    def __repr__(self):
        """String representation with non-default values."""
        parts = [f'name={self.name!r}']
        if self.model:
            parts.append(f'model={self.model.__name__}')
        if self.fields:
            parts.append(f'fields={self.fields!r}')
        if self.display_style != 'tabular':
            parts.append(f'display_style={self.display_style!r}')
        return f"Collection({', '.join(parts)})"

render_for_display(self, obj) -> dict

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

Render collection for display (related objects).

Args: obj: Model instance to get related objects from

Returns: Dict with collection display data: { 'type': 'collection', 'name': str, 'legend': str | None, 'items': list[dict], # Each item is rendered layout data }

Source code in layout.py line 354
    def render_for_display(self, obj) -> dict:
        """
        Render collection for display (related objects).

        Args:
            obj: Model instance to get related objects from

        Returns:
            Dict with collection display data:
            {
                'type': 'collection',
                'name': str,
                'legend': str | None,
                'items': list[dict],  # Each item is rendered layout data
            }
        """
        # Get related manager
        related_manager = getattr(obj, self.name, None)
        if related_manager is None:
            items = []
        elif hasattr(related_manager, 'all'):
            # It's a manager - get all related objects
            related_objects = related_manager.all()
            items = []

            for related_obj in related_objects:
                if self.layout:
                    # Use custom layout
                    item_data = self.layout.render_for_display(related_obj)
                else:
                    # Use fields list
                    item_data = []
                    for field_spec in self.fields:
                        if isinstance(field_spec, str):
                            field = Field(field_spec)
                        else:
                            field = field_spec
                        item_data.append(field.render_for_display(related_obj))

                items.append({'fields': item_data})
        else:
            items = []

        return {
            'type': 'collection',
            'name': self.name,
            'legend': self.legend or self.model._meta.verbose_name_plural.title(),
            'items': items,
        }

Fields

Field Type Related To
__dict__ getset_descriptor -
__weakref__ getset_descriptor -