Skip to main content

Introduction

Django Unfold provides a complete form system that extends Django’s admin forms with modern, styled components. The forms system includes custom widgets, fields, formsets with pagination, and seamless integration with Django’s admin interface.

Key Features

Custom Widgets

Pre-styled form widgets matching Unfold’s design system

Custom Fields

Enhanced form fields with autocomplete and special functionality

Pagination Support

Built-in pagination for inline formsets

Conditional Fields

Show/hide fields based on conditions

Form Classes

AdminForm

Unfold provides custom form wrapper classes that integrate with Django’s admin system:
from unfold.forms import AdminForm, Fieldset, Fieldline

# These classes are automatically used by Unfold's ModelAdmin
# You typically don't need to use them directly
The AdminForm, Fieldset, and Fieldline classes are automatically applied when using Unfold’s ModelAdmin. They handle the rendering of form fields with proper styling.

Authentication Forms

Custom authentication forms with Unfold styling:
from unfold.forms import (
    AuthenticationForm,
    UserCreationForm,
    UserChangeForm,
    AdminPasswordChangeForm,
    AdminOwnPasswordChangeForm,
)

# AuthenticationForm - Login form with Unfold styling
# UserCreationForm - User creation with password fields
# UserChangeForm - User edit form with password widget
# AdminPasswordChangeForm - Change another user's password
# AdminOwnPasswordChangeForm - Change own password

Example: Custom Login Form

admin.py
from django.contrib.admin import AdminSite
from unfold.forms import AuthenticationForm

class MyAdminSite(AdminSite):
    login_form = AuthenticationForm

admin_site = MyAdminSite(name='myadmin')

ActionForm

Custom action form for admin list views:
from unfold.forms import ActionForm

# Automatically applied to admin change lists
# Provides styled action dropdown

Formset Pagination

PaginationInlineFormSet

Paginate inline formsets to improve performance with large datasets:
admin.py
from django.contrib import admin
from unfold.admin import ModelAdmin
from unfold.forms import PaginationInlineFormSet
from .models import Author, Book

class BookInline(admin.TabularInline):
    model = Book
    formset = PaginationInlineFormSet
    extra = 0
    
    def get_formset(self, request, obj=None, **kwargs):
        formset = super().get_formset(request, obj, **kwargs)
        formset.request = request
        formset.per_page = 10  # Show 10 items per page
        return formset

@admin.register(Author)
class AuthorAdmin(ModelAdmin):
    inlines = [BookInline]

PaginationGenericInlineFormSet

Pagination support for generic inline formsets:
admin.py
from django.contrib.contenttypes.admin import GenericTabularInline
from unfold.forms import PaginationGenericInlineFormSet
from .models import Comment

class CommentInline(GenericTabularInline):
    model = Comment
    formset = PaginationGenericInlineFormSet
    extra = 0
    
    def get_formset(self, request, obj=None, **kwargs):
        formset = super().get_formset(request, obj, **kwargs)
        formset.request = request
        formset.per_page = 20
        return formset
When using pagination formsets, you must set formset.request and formset.per_page in the get_formset method.

Form Field Styling

All Unfold widgets come with pre-applied Tailwind CSS classes:
BASE_INPUT_CLASSES = [
    "border",
    "border-base-200",
    "bg-white",
    "font-medium",
    "rounded-default",
    "shadow-xs",
    "text-sm",
    "focus:outline-2",
    "focus:outline-primary-600",
    "dark:bg-base-900",
    "dark:border-base-700",
]

Search Forms

DatasetChangeListSearchForm

Custom search form for dataset change lists:
from unfold.forms import DatasetChangeListSearchForm

# Used internally for search functionality
# Automatically applied when using UNFOLD configuration

Form Validation

Unfold forms display validation errors with proper styling:
forms.py
from django import forms
from unfold.widgets import UnfoldAdminTextInputWidget

class MyForm(forms.Form):
    email = forms.EmailField(
        widget=UnfoldAdminTextInputWidget(attrs={
            'placeholder': 'Enter email'
        })
    )
    
    def clean_email(self):
        email = self.cleaned_data.get('email')
        if not email.endswith('@example.com'):
            raise forms.ValidationError('Email must be from example.com')
        return email
Validation errors are automatically styled with red borders and error messages below the field.

Password Fields

UnfoldReadOnlyPasswordHashWidget

Read-only widget for displaying password hashes:
from unfold.forms import UnfoldReadOnlyPasswordHashWidget

class UserChangeForm(forms.ModelForm):
    password = forms.CharField(
        widget=UnfoldReadOnlyPasswordHashWidget()
    )

Best Practices

Always use Unfold’s custom widgets to maintain consistent styling across your admin interface.
Use PaginationInlineFormSet for inline relationships with many related objects to improve performance.
Use autocomplete fields for foreign key relationships to improve user experience with large datasets.
Implement custom validation methods to provide clear feedback to users.

Next Steps

Custom Widgets

Explore all available form widgets

Custom Fields

Learn about enhanced form fields

Conditional Fields

Implement conditional field visibility

Crispy Forms

Integrate with Django Crispy Forms

Build docs developers (and LLMs) love