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

view-helpers.mddocs/

0

# View Helpers

1

2

Generic view components for creating tag-filtered list views and displaying objects by tag. Django-taggit provides utilities for implementing tag-based filtering in both function-based and class-based views.

3

4

## Capabilities

5

6

### Function-Based View Helper

7

8

Generic view function for listing objects filtered by a specific tag.

9

10

```python { .api }

11

def tagged_object_list(request, slug, queryset, **kwargs):

12

"""

13

Generic view function for listing objects with specific tag.

14

15

Parameters:

16

- request: HTTP request object

17

- slug (str): Tag slug to filter by

18

- queryset: Model queryset to filter

19

- **kwargs: Additional view parameters passed to generic view

20

21

Returns:

22

HttpResponse: Rendered template with filtered object list

23

24

Raises:

25

Http404: If tag with given slug does not exist

26

"""

27

```

28

29

```python

30

from django.shortcuts import render

31

from taggit.views import tagged_object_list

32

from myapp.models import Article

33

34

def articles_by_tag(request, slug):

35

return tagged_object_list(

36

request,

37

slug,

38

Article.objects.all(),

39

template_name='articles/tagged_list.html',

40

context_object_name='articles'

41

)

42

```

43

44

### Class-Based View Mixin

45

46

Mixin for class-based views that adds tag-based filtering functionality.

47

48

```python { .api }

49

class TagListMixin:

50

"""

51

Mixin for views filtering objects by tag.

52

53

Provides tag-based filtering functionality for class-based views,

54

particularly ListView, with automatic template name resolution

55

and context enhancement.

56

"""

57

tag_suffix = "_tag"

58

59

def dispatch(self, request, *args, **kwargs):

60

"""

61

Handle request dispatch with tag filtering setup.

62

63

Parameters:

64

- request: HTTP request object

65

- *args: Positional arguments

66

- **kwargs: Keyword arguments including 'slug' for tag

67

68

Returns:

69

HttpResponse: Response from parent dispatch method

70

71

Raises:

72

Http404: If tag with given slug does not exist

73

"""

74

75

def get_queryset(self, **kwargs):

76

"""

77

Return queryset filtered by tag.

78

79

Parameters:

80

- **kwargs: Additional filtering parameters

81

82

Returns:

83

QuerySet: Filtered queryset containing only objects with the tag

84

"""

85

86

def get_template_names(self):

87

"""

88

Return template names with tag-specific variants.

89

90

Adds template names with tag suffix to support

91

tag-specific templates while maintaining fallbacks.

92

93

Returns:

94

list: List of template names to try

95

"""

96

97

def get_context_data(self, **kwargs):

98

"""

99

Add tag context to template.

100

101

Parameters:

102

- **kwargs: Existing context data

103

104

Returns:

105

dict: Context dictionary with added 'tag' variable

106

"""

107

```

108

109

## Usage Examples

110

111

### Basic Function-Based View

112

113

Simple implementation using the tagged_object_list function.

114

115

```python

116

from django.urls import path

117

from taggit.views import tagged_object_list

118

from myapp.models import BlogPost

119

120

# In urls.py

121

urlpatterns = [

122

path('posts/tag/<slug:slug>/',

123

lambda request, slug: tagged_object_list(

124

request, slug, BlogPost.objects.published()

125

),

126

name='posts_by_tag'),

127

]

128

129

# Template: myapp/blogpost_list.html

130

# Context variables: object_list, tag

131

```

132

133

### Class-Based View with TagListMixin

134

135

Using the mixin with ListView for enhanced functionality.

136

137

```python

138

from django.views.generic import ListView

139

from taggit.views import TagListMixin

140

from myapp.models import Article

141

142

class ArticleTagListView(TagListMixin, ListView):

143

model = Article

144

context_object_name = 'articles'

145

paginate_by = 10

146

147

def get_queryset(self):

148

# Call parent to get tag-filtered queryset

149

queryset = super().get_queryset()

150

# Add additional filtering

151

return queryset.filter(published=True).order_by('-created_at')

152

153

# In urls.py

154

path('articles/tag/<slug:slug>/', ArticleTagListView.as_view(), name='articles_by_tag')

155

```

156

157

### Advanced Tag View Implementation

158

159

Custom view with additional features and error handling.

160

161

```python

162

from django.views.generic import ListView

163

from django.shortcuts import get_object_or_404

164

from django.db.models import Count

165

from taggit.models import Tag

166

from myapp.models import Article

167

168

class AdvancedTagView(ListView):

169

model = Article

170

template_name = 'articles/tag_detail.html'

171

context_object_name = 'articles'

172

paginate_by = 20

173

174

def dispatch(self, request, *args, **kwargs):

175

self.tag = get_object_or_404(Tag, slug=kwargs['slug'])

176

return super().dispatch(request, *args, **kwargs)

177

178

def get_queryset(self):

179

return Article.objects.filter(

180

tags=self.tag,

181

published=True

182

).select_related('author').order_by('-created_at')

183

184

def get_context_data(self, **kwargs):

185

context = super().get_context_data(**kwargs)

186

context.update({

187

'tag': self.tag,

188

'article_count': self.get_queryset().count(),

189

'related_tags': Tag.objects.filter(

190

article__in=self.get_queryset()

191

).exclude(id=self.tag.id).annotate(

192

usage_count=Count('article')

193

).order_by('-usage_count')[:10]

194

})

195

return context

196

```

197

198

### Multiple Tag Filtering

199

200

View that filters by multiple tags simultaneously.

201

202

```python

203

from django.views.generic import ListView

204

from django.db.models import Q

205

from taggit.models import Tag

206

207

class MultipleTagView(ListView):

208

model = Article

209

template_name = 'articles/multi_tag.html'

210

211

def get_queryset(self):

212

tag_slugs = self.request.GET.get('tags', '').split(',')

213

tag_slugs = [slug.strip() for slug in tag_slugs if slug.strip()]

214

215

if not tag_slugs:

216

return Article.objects.none()

217

218

# Get all specified tags

219

tags = Tag.objects.filter(slug__in=tag_slugs)

220

221

# Filter articles that have ALL specified tags

222

queryset = Article.objects.published()

223

for tag in tags:

224

queryset = queryset.filter(tags=tag)

225

226

return queryset.distinct()

227

228

def get_context_data(self, **kwargs):

229

context = super().get_context_data(**kwargs)

230

tag_slugs = self.request.GET.get('tags', '').split(',')

231

context['active_tags'] = Tag.objects.filter(

232

slug__in=[s.strip() for s in tag_slugs if s.strip()]

233

)

234

return context

235

236

# Usage: /articles/multi-tag/?tags=python,django,tutorial

237

```

238

239

### Tag Cloud View

240

241

View for displaying a tag cloud with usage counts.

242

243

```python

244

from django.views.generic import TemplateView

245

from django.db.models import Count

246

from taggit.models import Tag

247

248

class TagCloudView(TemplateView):

249

template_name = 'tags/cloud.html'

250

251

def get_context_data(self, **kwargs):

252

context = super().get_context_data(**kwargs)

253

254

# Get tags with usage counts

255

tags_with_counts = Tag.objects.annotate(

256

usage_count=Count('tagged_items')

257

).filter(usage_count__gt=0).order_by('name')

258

259

# Calculate relative sizes for cloud display

260

if tags_with_counts:

261

max_count = max(tag.usage_count for tag in tags_with_counts)

262

min_count = min(tag.usage_count for tag in tags_with_counts)

263

264

for tag in tags_with_counts:

265

if max_count == min_count:

266

tag.weight = 1.0

267

else:

268

tag.weight = (tag.usage_count - min_count) / (max_count - min_count)

269

270

context.update({

271

'tags': tags_with_counts,

272

'tag_count': tags_with_counts.count()

273

})

274

return context

275

```

276

277

### API Integration Views

278

279

Views for tag-related API endpoints.

280

281

```python

282

from django.http import JsonResponse

283

from django.views.generic import View

284

from django.db.models import Count

285

from taggit.models import Tag

286

287

class TagAutocompleteView(View):

288

"""Autocomplete API for tag suggestions."""

289

290

def get(self, request):

291

query = request.GET.get('q', '').strip()

292

if not query:

293

return JsonResponse({'tags': []})

294

295

tags = Tag.objects.filter(

296

name__icontains=query

297

).annotate(

298

usage_count=Count('tagged_items')

299

).order_by('-usage_count', 'name')[:10]

300

301

data = {

302

'tags': [

303

{

304

'name': tag.name,

305

'slug': tag.slug,

306

'usage_count': tag.usage_count

307

}

308

for tag in tags

309

]

310

}

311

return JsonResponse(data)

312

313

class PopularTagsView(View):

314

"""API endpoint for most popular tags."""

315

316

def get(self, request):

317

limit = int(request.GET.get('limit', 20))

318

tags = Tag.objects.annotate(

319

usage_count=Count('tagged_items')

320

).filter(usage_count__gt=0).order_by('-usage_count')[:limit]

321

322

data = {

323

'tags': [

324

{

325

'name': tag.name,

326

'slug': tag.slug,

327

'usage_count': tag.usage_count

328

}

329

for tag in tags

330

]

331

}

332

return JsonResponse(data)

333

```

334

335

## Template Integration

336

337

### Basic Template Structure

338

339

Templates for tag-filtered views with common patterns.

340

341

```html

342

<!-- articles/tagged_list.html -->

343

<h1>Articles tagged with "{{ tag.name }}"</h1>

344

345

<div class="tag-info">

346

<p>{{ articles|length }} article{{ articles|length|pluralize }} found</p>

347

</div>

348

349

<div class="articles">

350

{% for article in articles %}

351

<article class="article-summary">

352

<h2><a href="{{ article.get_absolute_url }}">{{ article.title }}</a></h2>

353

<p>{{ article.summary }}</p>

354

<div class="article-tags">

355

{% for article_tag in article.tags.all %}

356

<a href="{% url 'articles_by_tag' article_tag.slug %}"

357

class="tag {% if article_tag == tag %}current{% endif %}">

358

{{ article_tag.name }}

359

</a>

360

{% endfor %}

361

</div>

362

</article>

363

{% empty %}

364

<p>No articles found with tag "{{ tag.name }}".</p>

365

{% endfor %}

366

</div>

367

368

<!-- Pagination -->

369

{% if is_paginated %}

370

<div class="pagination">

371

{% if page_obj.has_previous %}

372

<a href="?page={{ page_obj.previous_page_number }}">Previous</a>

373

{% endif %}

374

375

<span class="page-info">

376

Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}

377

</span>

378

379

{% if page_obj.has_next %}

380

<a href="?page={{ page_obj.next_page_number }}">Next</a>

381

{% endif %}

382

</div>

383

{% endif %}

384

```

385

386

### Tag Cloud Template

387

388

Template for displaying tag clouds with weighted sizes.

389

390

```html

391

<!-- tags/cloud.html -->

392

<div class="tag-cloud">

393

<h2>Tag Cloud</h2>

394

<div class="cloud-container">

395

{% for tag in tags %}

396

<a href="{% url 'articles_by_tag' tag.slug %}"

397

class="cloud-tag"

398

style="font-size: {{ tag.weight|floatformat:1|add:'1' }}em;"

399

title="{{ tag.usage_count }} article{{ tag.usage_count|pluralize }}">

400

{{ tag.name }}

401

</a>

402

{% endfor %}

403

</div>

404

</div>

405

406

<style>

407

.tag-cloud {

408

margin: 2rem 0;

409

}

410

411

.cloud-container {

412

line-height: 1.8;

413

}

414

415

.cloud-tag {

416

display: inline-block;

417

margin: 0.2em 0.4em;

418

padding: 0.2em 0.4em;

419

background: #f0f0f0;

420

border-radius: 3px;

421

text-decoration: none;

422

color: #333;

423

transition: background 0.2s;

424

}

425

426

.cloud-tag:hover {

427

background: #e0e0e0;

428

}

429

</style>

430

```

431

432

## URL Configuration

433

434

### URL Patterns

435

436

Common URL patterns for tag-based views.

437

438

```python

439

# urls.py

440

from django.urls import path

441

from taggit.views import tagged_object_list

442

from myapp.views import (

443

ArticleTagListView, AdvancedTagView, MultipleTagView,

444

TagCloudView, TagAutocompleteView, PopularTagsView

445

)

446

from myapp.models import Article

447

448

app_name = 'tags'

449

450

urlpatterns = [

451

# Function-based view

452

path('articles/<slug:slug>/',

453

lambda request, slug: tagged_object_list(

454

request, slug, Article.objects.published()

455

),

456

name='articles_by_tag_simple'),

457

458

# Class-based views

459

path('articles/tag/<slug:slug>/',

460

ArticleTagListView.as_view(),

461

name='articles_by_tag'),

462

463

path('advanced/<slug:slug>/',

464

AdvancedTagView.as_view(),

465

name='advanced_tag_view'),

466

467

path('multi-tag/',

468

MultipleTagView.as_view(),

469

name='multi_tag_view'),

470

471

# Tag cloud

472

path('cloud/',

473

TagCloudView.as_view(),

474

name='tag_cloud'),

475

476

# API endpoints

477

path('api/autocomplete/',

478

TagAutocompleteView.as_view(),

479

name='tag_autocomplete'),

480

481

path('api/popular/',

482

PopularTagsView.as_view(),

483

name='popular_tags'),

484

]

485

```