Skip to content

Layout API Overview

The Layout API provides a powerful, declarative way to customize form layouts in django-admin-deux. It supports progressive enhancement: basic layouts work without plugins, while advanced features like inline editing and conditional fields are enabled when you install the djadmin-formset plugin.

Key Features

Core Features (No Plugin Required)

  • Fieldsets - Group fields with legends and descriptions
  • Rows - Horizontal field layouts using flexbox
  • Field Customization - Labels, widgets, help text, CSS classes
  • Widget Shortcuts - Use string names like 'textarea', 'email'
  • Django Admin Migration - Automatic conversion of fieldsets to Layout

Plugin Features (Requires djadmin-formset)

  • Collections - Inline editing of related objects
  • Conditional Fields - Show/hide fields based on values (show_if, hide_if)
  • Computed Fields - Auto-calculate values (calculate)
  • Client-side Validation - Instant feedback without page refresh
  • Drag-and-drop - Reorder inline items with is_sortable

Quick Start

Simple Layout (Core Only)

from djadmin import ModelAdmin, register, Layout, Field, Fieldset, Row

@register(Author)
class AuthorAdmin(ModelAdmin):
    layout = Layout(
        Fieldset('Personal Information',
            Row(
                Field('first_name', css_classes=['flex-1', 'pr-2']),
                Field('last_name', css_classes=['flex-1', 'pl-2']),
            ),
            Field('birth_date', label='Date of Birth'),
        ),
        Fieldset('Biography',
            Field('bio', widget='textarea', attrs={'rows': 8}),
        ),
    )

Result: Renders with fieldsets and flexbox rows. No plugin required!

With Inline Editing (Requires Plugin)

from djadmin import ModelAdmin, register, Layout, Field, Collection

@register(Author)
class AuthorAdmin(ModelAdmin):
    layout = Layout(
        Field('name'),
        Field('birth_date'),
        Collection('books',
            model=Book,
            fields=['title', 'isbn', 'published_date'],
            is_sortable=True,
        ),
    )

Without plugin: Error at startup with clear installation instructions With plugin: Full inline editing with drag-and-drop ordering

Installation

Core Only

pip install django-admin-deux
pip install django-admin-deux[djadmin-formset]

Or install separately:

pip install django-admin-deux
pip install django-formset

Components

The Layout API consists of 5 main components:

  1. Field - A single form field with customization options
  2. Fieldset - Groups fields with optional legend
  3. Row - Horizontal layout using flexbox
  4. Collection - Inline editing (requires plugin)
  5. Layout - Top-level container

Progressive Enhancement

The Layout API is designed for progressive enhancement:

Without Plugin                    With Plugin
├─ Fieldsets: ✓                  ├─ Everything core does, PLUS:
├─ Rows: ✓                        ├─ Collections (inline editing)
├─ Fields: ✓                      ├─ Conditional fields (show_if/hide_if)
├─ Widget shortcuts: ✓            ├─ Computed fields (calculate)
├─ Collections: ✗ (warning)       ├─ Client-side validation
├─ Conditional: ✗ (error)         └─ Drag-and-drop ordering
└─ Computed: ✗ (error)

Feature Validation

django-admin-deux validates features at startup to prevent runtime errors:

# This will fail at startup if plugin not installed
class ProductAdmin(ModelAdmin):
    layout = Layout(
        Field('name'),
        Field('weight', show_if=".type === 'physical'"),  # Needs plugin!
    )

Error message:

ImproperlyConfigured: Form for Product requires features that are not available:
  • Conditional fields (show_if/hide_if) require the djadmin-formset plugin.
    Install with: pip install django-admin-deux[djadmin-formset]

This fail-fast approach prevents production issues and guides developers to install required plugins.

Migration from Django Admin

The Layout API provides automatic conversion of Django admin fieldsets:

# Old Django admin code - JUST COPY IT!
class BookAdmin(admin.ModelAdmin):
    fieldsets = (
        ('Personal', {
            'fields': ('name', ('first_name', 'last_name'))
        }),
    )

# New djadmin - SAME CODE!
class BookAdmin(ModelAdmin):
    fieldsets = (  # ← Automatically converts to Layout
        ('Personal', {
            'fields': ('name', ('first_name', 'last_name'))
        }),
    )

The metaclass automatically converts fieldsets to Layout at class creation time.

See Django Admin Migration Guide for details.

Architecture

Core Rendering (Limited)

When no plugin is installed, layouts are rendered using Django templates:

  • Templates: djadmin/templates/djadmin/includes/
  • form_layout.html - Iterates layout items
  • form_field.html - Single field rendering
  • form_row.html - Flexbox row container
  • form_fieldset.html - Fieldset with legend
  • form_collection_warning.html - Warning for collections

  • Capabilities:

  • ✅ Fieldsets as <fieldset> tags
  • ✅ Rows as flexbox containers
  • ✅ Basic field rendering
  • ✅ Widget shortcuts
  • ❌ Collections show warning
  • ❌ Conditional fields cause error
  • ❌ Computed fields cause error

When djadmin-formset is installed:

  • Strategy: Plugin takes over ALL forms via djadmin_modify_form_class hook
  • Conversion: Layout → django-formset FormCollection
  • Renderer: DjAdminFormRenderer for themed rendering
  • Capabilities: Everything core does, plus all advanced features

Next Steps

Why Layout API?

Problems with Django Admin

  • Rigid fieldsets - Tuple syntax is hard to read and maintain
  • No horizontal layouts - All fields are stacked vertically
  • No inline customization - Limited control over inline appearance
  • No conditional logic - Can't show/hide fields dynamically

Layout API Solutions

  • Declarative - Clean, readable Python syntax
  • Flexible - Fieldsets, rows, and nested layouts
  • Progressive - Start simple, add features as needed
  • Type-safe - Dataclasses with validation
  • Extensible - Plugin system for advanced features
  • Compatible - Automatic Django admin migration

Philosophy

The Layout API follows these principles:

  1. Progressive Enhancement - Core features work standalone, plugins add capabilities
  2. Fail Fast - Feature validation at startup, not runtime
  3. Developer Experience - Clear error messages guide developers
  4. Flexibility - Support both simple and complex use cases
  5. Compatibility - Easy migration from Django admin

Support