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

form-integration.mddocs/

0

# Form Integration

1

2

Django forms integration for handling tag input and validation. Django-taggit provides form fields and widgets that make it easy to include tag functionality in Django forms with proper validation and user-friendly input methods.

3

4

## Capabilities

5

6

### TagField

7

8

A Django form field specifically designed for handling tag input as comma-separated values.

9

10

```python { .api }

11

class TagField(forms.CharField):

12

"""

13

Form field for handling tag input.

14

15

Inherits from CharField and provides tag-specific validation

16

and parsing of comma/space-separated tag input.

17

"""

18

widget = TagWidget

19

20

def clean(self, value):

21

"""

22

Clean and validate tag input.

23

24

Parameters:

25

- value (str): Raw input string from form

26

27

Returns:

28

list: Parsed list of tag names

29

30

Raises:

31

ValidationError: If input format is invalid

32

"""

33

34

def has_changed(self, initial_value, data_value):

35

"""

36

Check if field value has changed.

37

38

Parameters:

39

- initial_value: Original tag list

40

- data_value: New form input

41

42

Returns:

43

bool: True if tags have changed

44

"""

45

```

46

47

```python

48

from django import forms

49

from taggit.forms import TagField

50

51

class ArticleForm(forms.Form):

52

title = forms.CharField(max_length=200)

53

content = forms.CharField(widget=forms.Textarea)

54

tags = TagField()

55

56

# Usage in views

57

form = ArticleForm(data={'title': 'My Article', 'tags': 'python, django, tutorial'})

58

if form.is_valid():

59

tags = form.cleaned_data['tags'] # ['python', 'django', 'tutorial']

60

```

61

62

### Tag Widgets

63

64

Widget classes for rendering tag input fields in forms with appropriate formatting.

65

66

```python { .api }

67

class TagWidget(forms.TextInput):

68

"""

69

Text input widget for tag input.

70

71

Provides formatting for tag display in forms, converting

72

tag objects to comma-separated strings for editing.

73

"""

74

75

class TextareaTagWidget(forms.Textarea):

76

"""

77

Textarea widget for tag input.

78

79

Useful for cases where many tags are expected or

80

longer tag names are common.

81

"""

82

83

class TagWidgetMixin:

84

"""

85

Mixin providing tag formatting functionality.

86

87

Can be used with any form widget to add tag formatting.

88

"""

89

def format_value(self, value):

90

"""

91

Format tag objects for display in forms.

92

93

Parameters:

94

- value: Tag objects or string value

95

96

Returns:

97

str: Formatted tag string for form display

98

"""

99

```

100

101

### Admin Form Classes

102

103

Form classes specifically designed for admin interface functionality.

104

105

```python { .api }

106

class MergeTagsForm(forms.Form):

107

"""

108

Form for merging multiple tags into one.

109

110

Used in the admin interface to combine duplicate

111

or related tags into a single tag.

112

"""

113

new_tag_name = forms.CharField(

114

label="New Tag Name",

115

max_length=100,

116

help_text="Enter the name for the merged tag"

117

)

118

119

def clean_new_tag_name(self):

120

"""

121

Validate the new tag name.

122

123

Returns:

124

str: Cleaned tag name

125

"""

126

```

127

128

```python

129

from taggit.forms import TagField, TagWidget, TextareaTagWidget

130

131

class ArticleForm(forms.Form):

132

title = forms.CharField(max_length=200)

133

134

# Default text input widget

135

tags = TagField()

136

137

# Custom textarea widget for longer tag lists

138

keywords = TagField(widget=TextareaTagWidget(attrs={'rows': 3}))

139

140

# Custom styling

141

categories = TagField(

142

widget=TagWidget(attrs={

143

'class': 'form-control',

144

'placeholder': 'Enter tags separated by commas'

145

})

146

)

147

```

148

149

### ModelForm Integration

150

151

Integration with Django ModelForms for seamless tag handling in model forms.

152

153

```python

154

from django import forms

155

from taggit.forms import TagField

156

from myapp.models import Article

157

158

class ArticleModelForm(forms.ModelForm):

159

class Meta:

160

model = Article

161

fields = ['title', 'content', 'tags']

162

163

# TaggableManager fields are automatically handled

164

# but can be customized if needed

165

tags = TagField(

166

required=False,

167

help_text="Enter tags separated by commas"

168

)

169

```

170

171

### Custom Form Field Validation

172

173

Advanced validation patterns for tag input fields.

174

175

```python

176

from django import forms

177

from django.core.exceptions import ValidationError

178

from taggit.forms import TagField

179

180

class CustomTagField(TagField):

181

def clean(self, value):

182

tags = super().clean(value)

183

184

# Custom validation: limit number of tags

185

if len(tags) > 10:

186

raise ValidationError("Maximum 10 tags allowed")

187

188

# Custom validation: tag length

189

for tag in tags:

190

if len(tag) > 50:

191

raise ValidationError(f"Tag '{tag}' is too long (max 50 characters)")

192

193

# Custom validation: forbidden words

194

forbidden = ['spam', 'inappropriate']

195

for tag in tags:

196

if tag.lower() in forbidden:

197

raise ValidationError(f"Tag '{tag}' is not allowed")

198

199

return tags

200

201

class ArticleForm(forms.Form):

202

title = forms.CharField(max_length=200)

203

tags = CustomTagField()

204

```

205

206

### Form Processing

207

208

Complete examples of processing forms with tag fields.

209

210

```python

211

from django.shortcuts import render, redirect

212

from django.contrib import messages

213

from myapp.models import Article

214

from myapp.forms import ArticleForm

215

216

def create_article(request):

217

if request.method == 'POST':

218

form = ArticleForm(request.POST)

219

if form.is_valid():

220

# Create article

221

article = Article.objects.create(

222

title=form.cleaned_data['title'],

223

content=form.cleaned_data['content']

224

)

225

226

# Add tags

227

article.tags.set(form.cleaned_data['tags'])

228

229

messages.success(request, 'Article created successfully!')

230

return redirect('article_detail', pk=article.pk)

231

else:

232

form = ArticleForm()

233

234

return render(request, 'articles/create.html', {'form': form})

235

236

def edit_article(request, pk):

237

article = Article.objects.get(pk=pk)

238

239

if request.method == 'POST':

240

form = ArticleForm(request.POST)

241

if form.is_valid():

242

article.title = form.cleaned_data['title']

243

article.content = form.cleaned_data['content']

244

article.save()

245

246

# Update tags

247

article.tags.set(form.cleaned_data['tags'])

248

249

return redirect('article_detail', pk=article.pk)

250

else:

251

# Pre-populate form with existing tags

252

form = ArticleForm(initial={

253

'title': article.title,

254

'content': article.content,

255

'tags': ', '.join(article.tags.names())

256

})

257

258

return render(request, 'articles/edit.html', {'form': form, 'article': article})

259

```

260

261

### AJAX and Dynamic Forms

262

263

Implementing dynamic tag functionality with JavaScript and AJAX.

264

265

```python

266

from django.http import JsonResponse

267

from django.views.decorators.http import require_GET

268

from taggit.models import Tag

269

270

@require_GET

271

def tag_autocomplete(request):

272

"""

273

Provide tag suggestions for autocomplete functionality.

274

"""

275

term = request.GET.get('term', '')

276

if len(term) < 2:

277

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

278

279

tags = Tag.objects.filter(

280

name__icontains=term

281

).values_list('name', flat=True)[:10]

282

283

return JsonResponse({'suggestions': list(tags)})

284

285

# In template (example JavaScript for autocomplete)

286

"""

287

<script>

288

$('#id_tags').autocomplete({

289

source: "{% url 'tag_autocomplete' %}",

290

minLength: 2

291

});

292

</script>

293

"""

294

```

295

296

### Tag Input Parsing

297

298

Understanding how django-taggit parses different tag input formats.

299

300

```python

301

from taggit.utils import parse_tags

302

303

# Different input formats and their parsed results

304

examples = [

305

('python, django, tutorial', ['django', 'python', 'tutorial']),

306

('python django tutorial', ['django', 'python', 'tutorial']),

307

('"web development", python, django', ['django', 'python', 'web development']),

308

('python,django,tutorial', ['django', 'python', 'tutorial']),

309

('"multi word tag", single', ['multi word tag', 'single']),

310

]

311

312

for input_str, expected in examples:

313

result = parse_tags(input_str)

314

print(f"Input: {input_str}")

315

print(f"Parsed: {result}")

316

print(f"Expected: {expected}")

317

print("---")

318

```

319

320

### Form Rendering and Templates

321

322

Template examples for rendering tag forms with proper styling.

323

324

```html

325

<!-- Basic form rendering -->

326

<form method="post">

327

{% csrf_token %}

328

{{ form.as_p }}

329

<button type="submit">Save</button>

330

</form>

331

332

<!-- Custom form rendering -->

333

<form method="post">

334

{% csrf_token %}

335

<div class="form-group">

336

<label for="{{ form.title.id_for_label }}">Title:</label>

337

{{ form.title }}

338

{% if form.title.errors %}

339

<div class="error">{{ form.title.errors }}</div>

340

{% endif %}

341

</div>

342

343

<div class="form-group">

344

<label for="{{ form.tags.id_for_label }}">Tags:</label>

345

{{ form.tags }}

346

<small class="help-text">{{ form.tags.help_text }}</small>

347

{% if form.tags.errors %}

348

<div class="error">{{ form.tags.errors }}</div>

349

{% endif %}

350

</div>

351

352

<button type="submit" class="btn btn-primary">Save Article</button>

353

</form>

354

355

<!-- With Bootstrap styling -->

356

<div class="mb-3">

357

<label for="{{ form.tags.id_for_label }}" class="form-label">Tags</label>

358

<input type="{{ form.tags.widget.input_type }}"

359

name="{{ form.tags.name }}"

360

value="{{ form.tags.value|default:'' }}"

361

class="form-control{% if form.tags.errors %} is-invalid{% endif %}"

362

id="{{ form.tags.id_for_label }}"

363

placeholder="Enter tags separated by commas">

364

{% if form.tags.help_text %}

365

<div class="form-text">{{ form.tags.help_text }}</div>

366

{% endif %}

367

{% if form.tags.errors %}

368

<div class="invalid-feedback">

369

{% for error in form.tags.errors %}{{ error }}{% endfor %}

370

</div>

371

{% endif %}

372

</div>

373

```

374

375

### Formsets and Inline Forms

376

377

Using tag fields in Django formsets and inline forms.

378

379

```python

380

from django.forms import modelformset_factory

381

from myapp.models import Article

382

383

# Create formset with tag support

384

ArticleFormSet = modelformset_factory(

385

Article,

386

fields=['title', 'content', 'tags'],

387

extra=2

388

)

389

390

def bulk_edit_articles(request):

391

queryset = Article.objects.filter(author=request.user)

392

393

if request.method == 'POST':

394

formset = ArticleFormSet(request.POST, queryset=queryset)

395

if formset.is_valid():

396

formset.save()

397

return redirect('article_list')

398

else:

399

formset = ArticleFormSet(queryset=queryset)

400

401

return render(request, 'articles/bulk_edit.html', {'formset': formset})

402

```