or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

admin-interface.mdform-integration.mdindex.mdmodel-integration.mdrest-framework.mdtag-operations.mdutilities-management.mdview-helpers.md

admin-interface.mddocs/

0

# Admin Interface

1

2

Django admin integration for managing tags and tagged items. Django-taggit provides comprehensive admin interfaces for tag management, including search functionality, tag merging capabilities, and inline editing of tagged items.

3

4

## Capabilities

5

6

### TagAdmin

7

8

Admin interface for managing Tag objects with search, filtering, and bulk operations.

9

10

```python { .api }

11

class TagAdmin(admin.ModelAdmin):

12

"""

13

Admin interface for Tag model.

14

15

Features:

16

- List display with name and slug

17

- Search functionality by tag name

18

- Alphabetical ordering

19

- Prepopulated slug field

20

- Tag merging action

21

"""

22

list_display = ["name", "slug"]

23

ordering = ["name", "slug"]

24

search_fields = ["name"]

25

prepopulated_fields = {"slug": ["name"]}

26

actions = ["render_tag_form"]

27

28

def get_urls(self):

29

"""Add custom URLs for tag management."""

30

31

def render_tag_form(self, request, queryset):

32

"""Admin action to merge selected tags."""

33

34

def merge_tags_view(self, request):

35

"""View for handling tag merge operations."""

36

```

37

38

```python

39

# Register the Tag admin (automatically done by django-taggit)

40

from django.contrib import admin

41

from taggit.models import Tag

42

from taggit.admin import TagAdmin

43

44

admin.site.register(Tag, TagAdmin)

45

```

46

47

### TaggedItemInline

48

49

Inline admin for managing TaggedItem relationships within other model admin interfaces.

50

51

```python { .api }

52

class TaggedItemInline(admin.StackedInline):

53

"""

54

Inline admin for TaggedItem model.

55

56

Allows editing tag relationships directly within

57

the admin interface of tagged models.

58

"""

59

model = TaggedItem

60

```

61

62

```python

63

from django.contrib import admin

64

from taggit.admin import TaggedItemInline

65

from myapp.models import Article

66

67

class ArticleAdmin(admin.ModelAdmin):

68

list_display = ['title', 'created_at']

69

inlines = [TaggedItemInline]

70

71

admin.site.register(Article, ArticleAdmin)

72

```

73

74

### Custom Model Admin Integration

75

76

Integrating tagging functionality into your model admin interfaces.

77

78

```python

79

from django.contrib import admin

80

from taggit.models import Tag

81

82

class ArticleAdmin(admin.ModelAdmin):

83

list_display = ['title', 'author', 'created_at', 'tag_list']

84

list_filter = ['created_at', 'tags']

85

search_fields = ['title', 'content', 'tags__name']

86

87

def tag_list(self, obj):

88

"""Display tags in list view."""

89

return ', '.join([tag.name for tag in obj.tags.all()])

90

tag_list.short_description = 'Tags'

91

92

def get_queryset(self, request):

93

"""Optimize queries for tag display."""

94

return super().get_queryset(request).prefetch_related('tags')

95

96

admin.site.register(Article, ArticleAdmin)

97

```

98

99

### Tag Merging

100

101

Built-in functionality for merging multiple tags into a single tag.

102

103

```python { .api }

104

class MergeTagsForm(forms.Form):

105

"""

106

Form for merging multiple tags into one.

107

108

Used in the admin interface to combine duplicate

109

or related tags into a single tag.

110

"""

111

new_tag_name = forms.CharField(

112

label="New Tag Name",

113

max_length=100,

114

help_text="Enter new or existing tag name"

115

)

116

```

117

118

The tag merging process:

119

120

1. Select multiple tags in the admin interface

121

2. Choose "Merge selected tags" action

122

3. Enter the target tag name

123

4. All tagged items are transferred to the target tag

124

5. Original tags are deleted (except the target if it already existed)

125

126

### Advanced Admin Customizations

127

128

Custom admin configurations for enhanced tag management.

129

130

```python

131

from django.contrib import admin

132

from django.db.models import Count

133

from taggit.models import Tag, TaggedItem

134

135

class TaggedItemAdmin(admin.ModelAdmin):

136

list_display = ['tag', 'content_type', 'object_id', 'content_object']

137

list_filter = ['content_type', 'tag']

138

search_fields = ['tag__name']

139

raw_id_fields = ['tag']

140

141

class CustomTagAdmin(admin.ModelAdmin):

142

list_display = ['name', 'slug', 'usage_count', 'created_at']

143

list_filter = ['created_at']

144

search_fields = ['name', 'slug']

145

readonly_fields = ['slug', 'usage_count']

146

ordering = ['-usage_count', 'name']

147

148

def usage_count(self, obj):

149

"""Show how many times tag is used."""

150

return obj.tagged_items.count()

151

usage_count.short_description = 'Usage Count'

152

usage_count.admin_order_field = 'tagged_items__count'

153

154

def get_queryset(self, request):

155

"""Annotate with usage count for sorting."""

156

return super().get_queryset(request).annotate(

157

usage_count=Count('tagged_items')

158

)

159

160

# Register custom admin

161

admin.site.unregister(Tag)

162

admin.site.register(Tag, CustomTagAdmin)

163

admin.site.register(TaggedItem, TaggedItemAdmin)

164

```

165

166

### Filtering and Search

167

168

Advanced filtering and search capabilities in the admin interface.

169

170

```python

171

from django.contrib import admin

172

from django.db.models import Q

173

174

class TagFilter(admin.SimpleListFilter):

175

title = 'Tag'

176

parameter_name = 'tag'

177

178

def lookups(self, request, model_admin):

179

"""Provide tag options for filtering."""

180

tags = Tag.objects.all().order_by('name')[:50] # Limit for performance

181

return [(tag.id, tag.name) for tag in tags]

182

183

def queryset(self, request, queryset):

184

"""Filter queryset by selected tag."""

185

if self.value():

186

return queryset.filter(tags__id=self.value())

187

return queryset

188

189

class PopularTagFilter(admin.SimpleListFilter):

190

title = 'Tag Popularity'

191

parameter_name = 'popularity'

192

193

def lookups(self, request, model_admin):

194

return [

195

('popular', 'Popular (10+ uses)'),

196

('moderate', 'Moderate (5-9 uses)'),

197

('rare', 'Rare (1-4 uses)'),

198

('unused', 'Unused'),

199

]

200

201

def queryset(self, request, queryset):

202

from django.db.models import Count

203

204

if self.value() == 'popular':

205

return queryset.annotate(

206

usage=Count('tagged_items')

207

).filter(usage__gte=10)

208

elif self.value() == 'moderate':

209

return queryset.annotate(

210

usage=Count('tagged_items')

211

).filter(usage__range=(5, 9))

212

elif self.value() == 'rare':

213

return queryset.annotate(

214

usage=Count('tagged_items')

215

).filter(usage__range=(1, 4))

216

elif self.value() == 'unused':

217

return queryset.filter(tagged_items__isnull=True)

218

return queryset

219

220

class ArticleAdmin(admin.ModelAdmin):

221

list_display = ['title', 'author', 'tag_list']

222

list_filter = [TagFilter, 'created_at']

223

search_fields = ['title', 'content', 'tags__name']

224

225

def tag_list(self, obj):

226

return ', '.join([tag.name for tag in obj.tags.all()[:3]])

227

tag_list.short_description = 'Tags'

228

```

229

230

### Bulk Operations

231

232

Implementing bulk operations for tag management in the admin.

233

234

```python

235

from django.contrib import admin, messages

236

from django.shortcuts import redirect

237

238

class BulkTagAdmin(admin.ModelAdmin):

239

actions = ['add_tag_to_selected', 'remove_tag_from_selected', 'clear_tags_from_selected']

240

241

def add_tag_to_selected(self, request, queryset):

242

"""Add a specific tag to selected objects."""

243

tag_name = "bulk-processed" # Could be made configurable

244

count = 0

245

for obj in queryset:

246

obj.tags.add(tag_name)

247

count += 1

248

messages.success(request, f'Added tag "{tag_name}" to {count} objects.')

249

add_tag_to_selected.short_description = 'Add "bulk-processed" tag to selected items'

250

251

def remove_tag_from_selected(self, request, queryset):

252

"""Remove a specific tag from selected objects."""

253

tag_name = "draft"

254

count = 0

255

for obj in queryset:

256

obj.tags.remove(tag_name)

257

count += 1

258

messages.success(request, f'Removed tag "{tag_name}" from {count} objects.')

259

remove_tag_from_selected.short_description = 'Remove "draft" tag from selected items'

260

261

def clear_tags_from_selected(self, request, queryset):

262

"""Clear all tags from selected objects."""

263

count = 0

264

for obj in queryset:

265

obj.tags.clear()

266

count += 1

267

messages.success(request, f'Cleared all tags from {count} objects.')

268

clear_tags_from_selected.short_description = 'Clear all tags from selected items'

269

270

class ArticleAdmin(BulkTagAdmin):

271

list_display = ['title', 'author', 'tag_list']

272

# ... other configurations

273

```

274

275

### Custom Admin Templates

276

277

Customizing admin templates for enhanced tag management interfaces.

278

279

```html

280

<!-- admin/taggit/tag/change_list.html -->

281

{% extends "admin/change_list.html" %}

282

283

{% block extrahead %}

284

{{ block.super }}

285

<style>

286

.tag-usage-high { background-color: #d4edda; }

287

.tag-usage-medium { background-color: #fff3cd; }

288

.tag-usage-low { background-color: #f8d7da; }

289

</style>

290

{% endblock %}

291

292

{% block result_list %}

293

<script>

294

// Add visual indicators for tag usage

295

document.addEventListener('DOMContentLoaded', function() {

296

const rows = document.querySelectorAll('tbody tr');

297

rows.forEach(function(row) {

298

const usageCell = row.querySelector('td:nth-child(3)');

299

if (usageCell) {

300

const usage = parseInt(usageCell.textContent);

301

if (usage >= 10) {

302

row.classList.add('tag-usage-high');

303

} else if (usage >= 5) {

304

row.classList.add('tag-usage-medium');

305

} else if (usage > 0) {

306

row.classList.add('tag-usage-low');

307

}

308

}

309

});

310

});

311

</script>

312

{{ block.super }}

313

{% endblock %}

314

```

315

316

### Tag Statistics Dashboard

317

318

Creating a custom admin view for tag statistics and management.

319

320

```python

321

from django.contrib import admin

322

from django.urls import path

323

from django.shortcuts import render

324

from django.db.models import Count

325

from taggit.models import Tag

326

327

class TagStatsAdmin(admin.ModelAdmin):

328

change_list_template = 'admin/tag_stats.html'

329

330

def changelist_view(self, request, extra_context=None):

331

# Tag statistics

332

tag_stats = Tag.objects.annotate(

333

usage_count=Count('tagged_items')

334

).order_by('-usage_count')

335

336

popular_tags = tag_stats[:10]

337

unused_tags = tag_stats.filter(usage_count=0)

338

339

extra_context = extra_context or {}

340

extra_context.update({

341

'popular_tags': popular_tags,

342

'unused_tags_count': unused_tags.count(),

343

'total_tags': tag_stats.count(),

344

})

345

346

return super().changelist_view(request, extra_context=extra_context)

347

348

# Register with custom admin

349

admin.site.unregister(Tag)

350

admin.site.register(Tag, TagStatsAdmin)

351

```

352

353

```html

354

<!-- templates/admin/tag_stats.html -->

355

{% extends "admin/change_list.html" %}

356

357

{% block content_title %}

358

<h1>Tag Statistics</h1>

359

{% endblock %}

360

361

{% block result_list %}

362

<div class="results">

363

<div class="stats-summary">

364

<h2>Summary</h2>

365

<p>Total Tags: {{ total_tags }}</p>

366

<p>Unused Tags: {{ unused_tags_count }}</p>

367

</div>

368

369

<div class="popular-tags">

370

<h2>Most Popular Tags</h2>

371

<table>

372

<thead>

373

<tr>

374

<th>Tag</th>

375

<th>Usage Count</th>

376

</tr>

377

</thead>

378

<tbody>

379

{% for tag in popular_tags %}

380

<tr>

381

<td><a href="{% url 'admin:taggit_tag_change' tag.pk %}">{{ tag.name }}</a></td>

382

<td>{{ tag.usage_count }}</td>

383

</tr>

384

{% endfor %}

385

</tbody>

386

</table>

387

</div>

388

</div>

389

390

{{ block.super }}

391

{% endblock %}

392

```

393

394

### Permissions and Security

395

396

Managing permissions for tag administration.

397

398

```python

399

from django.contrib import admin

400

from django.contrib.auth.decorators import permission_required

401

402

class SecureTagAdmin(admin.ModelAdmin):

403

def has_delete_permission(self, request, obj=None):

404

"""Restrict tag deletion to superusers."""

405

return request.user.is_superuser

406

407

def has_change_permission(self, request, obj=None):

408

"""Allow tag editing for users with change permission."""

409

return request.user.has_perm('taggit.change_tag')

410

411

def get_queryset(self, request):

412

"""Filter tags based on user permissions."""

413

qs = super().get_queryset(request)

414

if not request.user.is_superuser:

415

# Regular users can only see tags they've created

416

# (requires custom Tag model with created_by field)

417

pass

418

return qs

419

420

# Custom permissions in models.py

421

class CustomTag(Tag):

422

created_by = models.ForeignKey('auth.User', on_delete=models.CASCADE)

423

424

class Meta:

425

permissions = [

426

('can_merge_tags', 'Can merge tags'),

427

('can_bulk_delete_tags', 'Can bulk delete tags'),

428

]

429

```