or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

admin-forms.mdcms-integration.mdconfiguration.mdfeeds-sitemaps.mdindex.mdmodels.mdtemplates-utilities.mdviews.md

admin-forms.mddocs/

0

# Admin and Forms

1

2

Advanced admin interface with placeholder editing, frontend editing, and comprehensive form handling for posts, categories, and configuration.

3

4

## Capabilities

5

6

### Post Administration

7

8

Comprehensive admin interface for blog post management with multilingual support and advanced editing features.

9

10

```python { .api }

11

class PostAdmin(PlaceholderAdminMixin, FrontendEditableAdminMixin, ModelAppHookConfig, TranslatableAdmin):

12

"""

13

Admin interface for blog posts.

14

15

Features:

16

- Multilingual editing with django-parler

17

- Placeholder field editing

18

- Frontend editing support

19

- Rich media management

20

- SEO field management

21

- Advanced filtering and search

22

"""

23

24

form: Type[PostAdminForm] = PostAdminForm

25

list_display: List[str] = [

26

'title', 'author', 'date_published', 'app_config', 'is_published'

27

]

28

list_filter: List[str] = [

29

'app_config', 'categories', 'date_published', 'featured'

30

]

31

search_fields: List[str] = ['translations__title', 'translations__abstract']

32

filter_horizontal: List[str] = ['categories', 'related']

33

readonly_fields: List[str] = ['created', 'modified']

34

date_hierarchy: str = 'date_published'

35

36

fieldsets: List[Tuple[str, Dict[str, Any]]] = [

37

(None, {

38

'fields': (

39

'title', 'subtitle', 'slug', 'abstract', 'post_text',

40

'author', 'date_published', 'date_featured',

41

'enable_comments', 'featured', 'liveblog', 'include_in_rss'

42

)

43

}),

44

('Images', {

45

'fields': ('main_image', 'main_image_thumbnail', 'main_image_full'),

46

'classes': ('collapse',)

47

}),

48

('SEO', {

49

'fields': ('meta_title', 'meta_description', 'meta_keywords'),

50

'classes': ('collapse',)

51

}),

52

('Relationships', {

53

'fields': ('categories', 'tags', 'related', 'sites'),

54

'classes': ('collapse',)

55

}),

56

('Advanced', {

57

'fields': ('app_config', 'created', 'modified'),

58

'classes': ('collapse',)

59

})

60

]

61

62

def get_queryset(self, request: HttpRequest) -> QuerySet:

63

"""Return queryset filtered by app config permissions."""

64

65

def get_form(self, request: HttpRequest, obj: Optional[Post] = None, **kwargs) -> Type[ModelForm]:

66

"""Return form class with proper configuration."""

67

68

def save_model(self, request: HttpRequest, obj: Post, form: ModelForm, change: bool) -> None:

69

"""Save model with additional processing."""

70

71

def get_prepopulated_fields(self, request: HttpRequest, obj: Optional[Post] = None) -> Dict[str, List[str]]:

72

"""Return fields for automatic slug population."""

73

74

def is_published(self, obj: Post) -> bool:

75

"""Check if post is published for list display."""

76

is_published.boolean = True

77

is_published.short_description = 'Published'

78

```

79

80

### Category Administration

81

82

Admin interface for blog category management with hierarchical support.

83

84

```python { .api }

85

class BlogCategoryAdmin(ModelAppHookConfig, TranslatableAdmin):

86

"""

87

Admin interface for blog categories.

88

89

Features:

90

- Multilingual category management

91

- Hierarchical category organization

92

- SEO field management

93

- App configuration filtering

94

"""

95

96

form: Type[CategoryAdminForm] = CategoryAdminForm

97

list_display: List[str] = ['name', 'app_config', 'parent']

98

list_filter: List[str] = ['app_config', 'parent']

99

search_fields: List[str] = ['translations__name']

100

101

fieldsets: List[Tuple[str, Dict[str, Any]]] = [

102

(None, {

103

'fields': ('name', 'slug', 'parent', 'app_config')

104

}),

105

('SEO', {

106

'fields': ('meta_title', 'meta_description', 'meta_keywords'),

107

'classes': ('collapse',)

108

})

109

]

110

111

def get_prepopulated_fields(self, request: HttpRequest, obj: Optional[BlogCategory] = None) -> Dict[str, List[str]]:

112

"""Return fields for automatic slug population."""

113

```

114

115

### Configuration Administration

116

117

Admin interface for blog configuration management.

118

119

```python { .api }

120

class BlogConfigAdmin(BaseAppHookConfig, TranslatableAdmin):

121

"""

122

Admin interface for blog configuration.

123

124

Features:

125

- Per-apphook configuration

126

- Multilingual configuration options

127

- Template and permalink settings

128

- SEO and social media settings

129

"""

130

131

def namespace_valid(self, obj: BlogConfig) -> bool:

132

"""Validate namespace configuration."""

133

```

134

135

### Site Filtering

136

137

Custom admin filter for multi-site support.

138

139

```python { .api }

140

class SiteListFilter(admin.SimpleListFilter):

141

"""

142

Admin list filter for site-specific filtering.

143

144

Features:

145

- Filter posts by site

146

- Multi-site deployment support

147

- Permission-based filtering

148

"""

149

150

title: str = 'Site'

151

parameter_name: str = 'site'

152

153

def lookups(self, request: HttpRequest, model_admin: admin.ModelAdmin) -> List[Tuple[str, str]]:

154

"""Return available site options."""

155

156

def queryset(self, request: HttpRequest, queryset: QuerySet) -> QuerySet:

157

"""Filter queryset by selected site."""

158

```

159

160

### Form Classes

161

162

Comprehensive form classes for blog content management.

163

164

```python { .api }

165

class ConfigFormBase:

166

"""

167

Base class for configuration forms.

168

169

Features:

170

- App configuration filtering

171

- Dynamic field generation

172

- Validation helpers

173

"""

174

175

def __init__(self, **kwargs) -> None:

176

"""Initialize form with app config filtering."""

177

178

def filter_by_app_config(self, field_name: str, queryset: QuerySet) -> QuerySet:

179

"""Filter form field queryset by app configuration."""

180

181

class PostAdminFormBase(ConfigFormBase, TranslatableModelForm):

182

"""

183

Base admin form for posts.

184

185

Features:

186

- Multilingual form handling

187

- Category and tag management

188

- SEO field validation

189

- Slug generation

190

"""

191

192

class Meta:

193

model: Type[Post] = Post

194

fields: str = '__all__'

195

196

def __init__(self, *args, **kwargs) -> None:

197

"""Initialize form with proper field configuration."""

198

199

def clean_slug(self) -> str:

200

"""Validate and generate slug."""

201

202

def clean(self) -> Dict[str, Any]:

203

"""Perform cross-field validation."""

204

205

class PostAdminForm(PostAdminFormBase):

206

"""

207

Main admin form for blog posts.

208

209

Fields:

210

- All Post model fields

211

- Custom validation logic

212

- Dynamic field filtering

213

"""

214

215

def __init__(self, *args, **kwargs) -> None:

216

"""Initialize with complete field set."""

217

218

class CategoryAdminForm(ConfigFormBase, TranslatableModelForm):

219

"""

220

Admin form for blog categories.

221

222

Features:

223

- Hierarchical category selection

224

- App configuration filtering

225

- SEO field management

226

"""

227

228

class Meta:

229

model: Type[BlogCategory] = BlogCategory

230

fields: str = '__all__'

231

232

class BlogPluginForm(forms.ModelForm):

233

"""

234

Base form for blog plugins.

235

236

Features:

237

- Template selection

238

- App configuration filtering

239

- Plugin-specific validation

240

"""

241

242

class Meta:

243

model: Type[BasePostPlugin] = BasePostPlugin

244

fields: str = '__all__'

245

246

class LatestEntriesForm(BlogPluginForm):

247

"""

248

Form for latest entries plugin.

249

250

Fields:

251

- latest_posts: IntegerField

252

- tags: ModelMultipleChoiceField

253

- categories: ModelMultipleChoiceField

254

- template: ChoiceField

255

"""

256

257

class Meta:

258

model: Type[LatestPostsPlugin] = LatestPostsPlugin

259

fields: str = '__all__'

260

261

class AuthorPostsForm(BlogPluginForm):

262

"""

263

Form for author posts plugin.

264

265

Fields:

266

- authors: ModelMultipleChoiceField

267

- latest_posts: IntegerField

268

- template: ChoiceField

269

"""

270

271

class Meta:

272

model: Type[AuthorEntriesPlugin] = AuthorEntriesPlugin

273

fields: str = '__all__'

274

```

275

276

## Admin Usage Examples

277

278

```python

279

# Customizing admin interface

280

from django.contrib import admin

281

from djangocms_blog.models import Post, BlogCategory

282

from djangocms_blog.admin import PostAdmin, BlogCategoryAdmin

283

284

# Customize post admin

285

class CustomPostAdmin(PostAdmin):

286

"""Custom post admin with additional features."""

287

288

list_display = PostAdmin.list_display + ['custom_field']

289

list_filter = PostAdmin.list_filter + ['custom_category']

290

291

fieldsets = PostAdmin.fieldsets + [

292

('Custom Fields', {

293

'fields': ('custom_field', 'custom_category'),

294

'classes': ('collapse',)

295

})

296

]

297

298

def get_queryset(self, request):

299

"""Custom queryset filtering."""

300

qs = super().get_queryset(request)

301

if not request.user.is_superuser:

302

qs = qs.filter(author=request.user)

303

return qs

304

305

# Re-register with custom admin

306

admin.site.unregister(Post)

307

admin.site.register(Post, CustomPostAdmin)

308

309

# Custom form validation

310

from djangocms_blog.forms import PostAdminForm

311

312

class CustomPostAdminForm(PostAdminForm):

313

"""Custom post form with additional validation."""

314

315

def clean_title(self):

316

"""Custom title validation."""

317

title = self.cleaned_data.get('title')

318

if title and len(title) < 10:

319

raise forms.ValidationError('Title must be at least 10 characters long.')

320

return title

321

322

def clean(self):

323

"""Custom cross-field validation."""

324

cleaned_data = super().clean()

325

date_published = cleaned_data.get('date_published')

326

featured = cleaned_data.get('featured')

327

328

if featured and not date_published:

329

raise forms.ValidationError('Featured posts must have a publication date.')

330

331

return cleaned_data

332

333

# Using forms in custom views

334

from djangocms_blog.forms import PostAdminForm

335

from django.views.generic import CreateView

336

337

class CustomPostCreateView(CreateView):

338

"""Custom view for post creation."""

339

340

model = Post

341

form_class = PostAdminForm

342

template_name = 'custom/post_create.html'

343

344

def form_valid(self, form):

345

"""Set author before saving."""

346

form.instance.author = self.request.user

347

return super().form_valid(form)

348

349

# Admin action examples

350

from django.contrib import admin

351

from django.utils.translation import gettext_lazy as _

352

353

@admin.action(description=_('Mark selected posts as featured'))

354

def make_featured(modeladmin, request, queryset):

355

"""Admin action to mark posts as featured."""

356

queryset.update(featured=True)

357

358

@admin.action(description=_('Publish selected posts'))

359

def publish_posts(modeladmin, request, queryset):

360

"""Admin action to publish posts."""

361

from django.utils import timezone

362

queryset.update(date_published=timezone.now())

363

364

# Add actions to admin

365

class EnhancedPostAdmin(PostAdmin):

366

actions = [make_featured, publish_posts]

367

368

# Custom admin templates

369

# Create templates in:

370

# templates/admin/djangocms_blog/post/change_form.html

371

# templates/admin/djangocms_blog/post/change_list.html

372

```