or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

admin-interface.mdapi.mdcontent-fields.mdcontrib.mdindex.mdmedia.mdpage-models.mdsearch.mdsystem-integration.mdtemplates.mdworkflows.md

admin-interface.mddocs/

0

# Admin Interface and Panels

1

2

Customizable admin interface with panel system for organizing edit forms, menu configuration, and extensible admin UI components. Wagtail's admin interface provides a user-friendly content management experience with powerful customization capabilities.

3

4

## Capabilities

5

6

### Panel System

7

8

Panel classes for organizing edit forms and controlling the admin interface layout.

9

10

```python { .api }

11

class Panel:

12

"""

13

Base panel class for edit forms.

14

15

All panel types inherit from this base class.

16

"""

17

def __init__(self, heading='', classname='', help_text='', **kwargs):

18

"""

19

Initialize panel with display options.

20

21

Parameters:

22

heading (str): Panel heading text

23

classname (str): CSS class for styling

24

help_text (str): Help text displayed to users

25

"""

26

27

class FieldPanel(Panel):

28

"""

29

Panel for editing a single model field.

30

31

The most commonly used panel type for basic field editing.

32

"""

33

def __init__(self, field_name, widget=None, heading='', classname='', help_text='', **kwargs):

34

"""

35

Initialize field panel.

36

37

Parameters:

38

field_name (str): Name of the model field to edit

39

widget (Widget): Custom form widget to use

40

heading (str): Custom heading for the field

41

classname (str): CSS class for styling

42

help_text (str): Help text for the field

43

"""

44

45

class MultiFieldPanel(Panel):

46

"""

47

Panel that groups multiple fields together under a common heading.

48

"""

49

def __init__(self, children, heading='', classname='', help_text='', **kwargs):

50

"""

51

Initialize multi-field panel.

52

53

Parameters:

54

children (list): List of child panels to group

55

heading (str): Heading for the group

56

classname (str): CSS class for styling

57

help_text (str): Help text for the group

58

"""

59

60

class TitleFieldPanel(FieldPanel):

61

"""

62

Special panel for title fields that enables automatic slug generation.

63

"""

64

def __init__(self, field_name, **kwargs):

65

"""Initialize title field panel with slug generation."""

66

67

class PublishingPanel(Panel):

68

"""

69

Panel that displays publishing workflow controls and status.

70

"""

71

def __init__(self, **kwargs):

72

"""Initialize publishing panel."""

73

74

class CommentPanel(Panel):

75

"""

76

Panel that displays the comments interface for collaborative editing.

77

"""

78

def __init__(self, **kwargs):

79

"""Initialize comment panel."""

80

81

class InlinePanel(Panel):

82

"""

83

Panel for editing related objects inline within the parent object's form.

84

"""

85

def __init__(self, relation_name, panels=None, heading='', label='', min_num=None, max_num=None, classname='', help_text='', **kwargs):

86

"""

87

Initialize inline panel.

88

89

Parameters:

90

relation_name (str): Name of the foreign key relation

91

panels (list): List of panels for editing related objects

92

heading (str): Panel heading

93

label (str): Label for individual items

94

min_num (int): Minimum number of items required

95

max_num (int): Maximum number of items allowed

96

classname (str): CSS class for styling

97

help_text (str): Help text for the panel

98

"""

99

100

class ObjectList(Panel):

101

"""

102

Container for organizing multiple panels into logical groups.

103

"""

104

def __init__(self, children, heading='', classname='', **kwargs):

105

"""

106

Initialize object list.

107

108

Parameters:

109

children (list): List of child panels

110

heading (str): Group heading

111

classname (str): CSS class for styling

112

"""

113

114

class TabbedInterface(Panel):

115

"""

116

Creates a tabbed interface with multiple panel groups.

117

"""

118

def __init__(self, children, **kwargs):

119

"""

120

Initialize tabbed interface.

121

122

Parameters:

123

children (list): List of ObjectList panels for each tab

124

"""

125

```

126

127

### Menu System

128

129

Classes for customizing the admin navigation menu.

130

131

```python { .api }

132

class MenuItem:

133

"""

134

Individual menu item in the admin interface.

135

"""

136

def __init__(self, label, url, name=None, icon_name=None, attrs=None, order=1000, **kwargs):

137

"""

138

Initialize menu item.

139

140

Parameters:

141

label (str): Display text for the menu item

142

url (str): URL the menu item links to

143

name (str): Unique identifier for the menu item

144

icon_name (str): Icon to display with the menu item

145

attrs (dict): Additional HTML attributes

146

order (int): Sort order for menu positioning

147

"""

148

149

class Menu:

150

"""

151

Container for organizing menu items.

152

"""

153

def __init__(self, register_hook_name=None, construct_hook_name=None):

154

"""Initialize menu container."""

155

156

def register_menu_item(self, menu_item):

157

"""Register a menu item with this menu."""

158

159

class SubmenuMenuItem(MenuItem):

160

"""

161

Menu item that contains nested menu items.

162

"""

163

def __init__(self, label, menu, **kwargs):

164

"""

165

Initialize submenu item.

166

167

Parameters:

168

label (str): Display text for the submenu

169

menu (Menu): Menu object containing child items

170

"""

171

```

172

173

### ViewSets

174

175

ViewSet classes for creating complete admin interfaces for models.

176

177

```python { .api }

178

class ViewSet:

179

"""

180

Base viewset class providing a collection of views for a specific functionality.

181

"""

182

name: str

183

url_prefix: str

184

185

def get_urlpatterns(self):

186

"""Get URL patterns for this viewset."""

187

188

def get_admin_menu_item(self):

189

"""Get menu item for admin navigation."""

190

191

class ModelViewSet(ViewSet):

192

"""

193

Complete CRUD interface for Django models.

194

195

Provides list, create, edit, delete, and inspect views.

196

"""

197

model: Model

198

form_class: ModelForm

199

index_template_name: str

200

create_template_name: str

201

edit_template_name: str

202

delete_template_name: str

203

204

def __init__(self, name, model=None, **kwargs):

205

"""

206

Initialize model viewset.

207

208

Parameters:

209

name (str): Unique name for the viewset

210

model (Model): Django model to manage

211

"""

212

213

def get_queryset(self, request):

214

"""Get the queryset for listing objects."""

215

216

def get_form_class(self, for_update=False):

217

"""Get the form class for creating/editing objects."""

218

219

def get_edit_handler(self):

220

"""Get the edit handler (panel configuration) for forms."""

221

222

class PageViewSet(ModelViewSet):

223

"""

224

Specialized viewset for page models with additional page-specific functionality.

225

"""

226

template_name: str

227

228

def get_edit_handler(self):

229

"""Get edit handler with page-specific panels."""

230

```

231

232

### Admin Forms and Widgets

233

234

Form classes and widgets for the admin interface.

235

236

```python { .api }

237

class WagtailAdminModelForm(forms.ModelForm):

238

"""

239

Base form class for Wagtail admin forms.

240

241

Provides consistent styling and functionality.

242

"""

243

def __init__(self, *args, **kwargs):

244

"""Initialize admin form with Wagtail styling."""

245

246

class WagtailAdminPageForm(WagtailAdminModelForm):

247

"""

248

Form class specifically for page editing with additional page functionality.

249

"""

250

def clean(self):

251

"""Validate page-specific constraints."""

252

253

# Widget classes for form fields

254

class AdminAutoHeightTextInput(forms.Textarea):

255

"""Text input that automatically adjusts height."""

256

257

class AdminPageChooser(forms.Select):

258

"""Widget for choosing pages with search interface."""

259

260

class AdminImageChooser(forms.ClearableFileInput):

261

"""Widget for choosing images with preview."""

262

263

class AdminDocumentChooser(forms.ClearableFileInput):

264

"""Widget for choosing documents with metadata."""

265

266

class AdminTagWidget(forms.TextInput):

267

"""Widget for tag input with autocomplete."""

268

269

class AdminDateInput(forms.DateInput):

270

"""Date input widget with calendar picker."""

271

272

class AdminTimeInput(forms.TimeInput):

273

"""Time input widget with time picker."""

274

275

class AdminDateTimeInput(forms.DateTimeInput):

276

"""DateTime input widget with combined picker."""

277

```

278

279

### Permission System

280

281

Classes for managing admin permissions and access control.

282

283

```python { .api }

284

class PermissionHelper:

285

"""

286

Helper class for checking permissions in admin views.

287

"""

288

def __init__(self, model, inspect_view_enabled=False):

289

"""

290

Initialize permission helper.

291

292

Parameters:

293

model (Model): Model to check permissions for

294

inspect_view_enabled (bool): Whether inspect view is available

295

"""

296

297

def user_can_list(self, user):

298

"""Check if user can view the listing page."""

299

300

def user_can_create(self, user):

301

"""Check if user can create new objects."""

302

303

def user_can_inspect_obj(self, user, obj):

304

"""Check if user can inspect a specific object."""

305

306

def user_can_edit_obj(self, user, obj):

307

"""Check if user can edit a specific object."""

308

309

def user_can_delete_obj(self, user, obj):

310

"""Check if user can delete a specific object."""

311

312

class PagePermissionHelper(PermissionHelper):

313

"""

314

Permission helper specifically for page models with page-specific permissions.

315

"""

316

def user_can_edit_obj(self, user, obj):

317

"""Check page-specific edit permissions."""

318

```

319

320

## Usage Examples

321

322

### Customizing Page Edit Interface

323

324

```python

325

from wagtail.models import Page

326

from wagtail.fields import RichTextField, StreamField

327

from wagtail.admin.panels import (

328

FieldPanel, MultiFieldPanel, InlinePanel, TabbedInterface, ObjectList

329

)

330

from django.db import models

331

332

class BlogPage(Page):

333

"""Blog page with custom admin interface."""

334

date = models.DateField("Post date")

335

intro = models.CharField(max_length=250)

336

body = RichTextField(blank=True)

337

featured_image = models.ForeignKey(

338

'wagtailimages.Image',

339

null=True,

340

blank=True,

341

on_delete=models.SET_NULL,

342

related_name='+'

343

)

344

345

# Organize fields into logical groups

346

content_panels = Page.content_panels + [

347

MultiFieldPanel([

348

FieldPanel('date'),

349

FieldPanel('intro'),

350

], heading="Article Information"),

351

FieldPanel('body'),

352

FieldPanel('featured_image'),

353

]

354

355

# Create tabbed interface

356

edit_handler = TabbedInterface([

357

ObjectList(content_panels, heading='Content'),

358

ObjectList(Page.promote_panels, heading='Promote'),

359

ObjectList(Page.settings_panels, heading='Settings'),

360

])

361

```

362

363

### Creating Custom Admin Views

364

365

```python

366

from wagtail.admin.viewsets import ModelViewSet

367

from wagtail.admin.ui.tables import Column, DateColumn

368

from django.db import models

369

370

class EventPage(Page):

371

"""Event page model."""

372

event_date = models.DateField()

373

location = models.CharField(max_length=255)

374

capacity = models.IntegerField()

375

376

class EventPageViewSet(ModelViewSet):

377

"""Custom admin interface for events."""

378

model = EventPage

379

icon = 'date'

380

menu_label = 'Events'

381

menu_order = 200

382

add_to_settings_menu = False

383

384

# Customize the listing page

385

list_display = ['title', 'event_date', 'location', 'capacity', 'live']

386

list_filter = ['event_date', 'live']

387

search_fields = ['title', 'location']

388

389

# Custom columns for the listing

390

def get_columns(self):

391

return [

392

Column('title', label='Event Title', sort_key='title'),

393

DateColumn('event_date', label='Date', sort_key='event_date'),

394

Column('location', label='Location'),

395

Column('capacity', label='Capacity'),

396

]

397

398

# Register the viewset

399

event_viewset = EventPageViewSet('events')

400

```

401

402

### Adding Custom Menu Items

403

404

```python

405

from wagtail import hooks

406

from wagtail.admin.menu import MenuItem, Menu, SubmenuMenuItem

407

from django.urls import reverse, path

408

from django.http import HttpResponse

409

410

@hooks.register('register_admin_urls')

411

def register_admin_urls():

412

"""Register custom admin URLs."""

413

return [

414

path('reports/', my_reports_view, name='my_reports'),

415

path('tools/', my_tools_view, name='my_tools'),

416

]

417

418

def my_reports_view(request):

419

"""Custom reports view."""

420

return HttpResponse('<h1>Reports</h1>')

421

422

def my_tools_view(request):

423

"""Custom tools view."""

424

return HttpResponse('<h1>Tools</h1>')

425

426

@hooks.register('construct_main_menu')

427

def add_reports_menu_item(request, menu_items):

428

"""Add reports to main menu."""

429

menu_items.append(

430

MenuItem(

431

'Reports',

432

reverse('my_reports'),

433

icon_name='doc-full-inverse',

434

order=300

435

)

436

)

437

438

@hooks.register('construct_main_menu')

439

def add_tools_submenu(request, menu_items):

440

"""Add tools submenu."""

441

tools_menu = Menu()

442

tools_menu.register_menu_item(

443

MenuItem('Tool 1', reverse('my_tools'), icon_name='cog')

444

)

445

446

menu_items.append(

447

SubmenuMenuItem(

448

'Tools',

449

tools_menu,

450

icon_name='cogs',

451

order=400

452

)

453

)

454

```

455

456

### Custom Form Widgets

457

458

```python

459

from wagtail.admin.widgets import AdminPageChooser, AdminImageChooser

460

from wagtail.admin.panels import FieldPanel

461

from django import forms

462

from django.db import models

463

464

class CustomWidget(forms.TextInput):

465

"""Custom admin widget with special functionality."""

466

template_name = 'admin/widgets/custom_widget.html'

467

468

class Media:

469

css = {'all': ('css/custom-widget.css',)}

470

js = ('js/custom-widget.js',)

471

472

class LandingPage(Page):

473

"""Landing page with custom form widgets."""

474

related_page = models.ForeignKey(

475

'wagtailcore.Page',

476

null=True,

477

blank=True,

478

on_delete=models.SET_NULL

479

)

480

hero_image = models.ForeignKey(

481

'wagtailimages.Image',

482

null=True,

483

blank=True,

484

on_delete=models.SET_NULL

485

)

486

special_field = models.CharField(max_length=100)

487

488

content_panels = Page.content_panels + [

489

FieldPanel('related_page', widget=AdminPageChooser(page_type='blog.BlogPage')),

490

FieldPanel('hero_image', widget=AdminImageChooser()),

491

FieldPanel('special_field', widget=CustomWidget()),

492

]

493

```

494

495

### Inline Editing

496

497

```python

498

from wagtail.models import Orderable

499

from modelcluster.fields import ParentalKey

500

501

class GalleryImage(Orderable):

502

"""Individual image in a gallery."""

503

page = ParentalKey('GalleryPage', related_name='gallery_images', on_delete=models.CASCADE)

504

image = models.ForeignKey('wagtailimages.Image', on_delete=models.CASCADE)

505

caption = models.CharField(max_length=250, blank=True)

506

507

panels = [

508

FieldPanel('image'),

509

FieldPanel('caption'),

510

]

511

512

class GalleryPage(Page):

513

"""Page with inline image gallery editing."""

514

intro = RichTextField(blank=True)

515

516

content_panels = Page.content_panels + [

517

FieldPanel('intro'),

518

InlinePanel(

519

'gallery_images',

520

label="Gallery Images",

521

min_num=1,

522

max_num=20,

523

heading="Image Gallery"

524

),

525

]

526

```