Django template tags and filters for customizing form field rendering without modifying Python form definitions.
npx @tessl/cli install tessl/pypi-django-widget-tweaks@1.5.00
# Django Widget Tweaks
1
2
Django Widget Tweaks provides template-level control over form field rendering without requiring Python-level form definitions. It offers template tags and filters for customizing HTML attributes, CSS classes, and field properties directly in Django templates, enabling clean separation between presentation logic and business logic.
3
4
## Package Information
5
6
- **Package Name**: django-widget-tweaks
7
- **Package Type**: pypi
8
- **Language**: Python
9
- **Installation**: `pip install django-widget-tweaks`
10
- **Django Setup**: Add `'widget_tweaks'` to `INSTALLED_APPS` in settings.py
11
12
## Core Imports
13
14
```python
15
# Load in Django templates
16
{% load widget_tweaks %}
17
```
18
19
## Basic Usage
20
21
```html
22
{% load widget_tweaks %}
23
24
<!-- Basic attribute modification -->
25
{{ form.name|attr:"placeholder:Enter your name" }}
26
27
<!-- Add CSS classes -->
28
{{ form.email|add_class:"form-control email-input" }}
29
30
<!-- Use render_field tag for HTML-like syntax -->
31
{% render_field form.message rows="5" cols="40" placeholder="Your message" %}
32
33
<!-- Conditional styling based on field state -->
34
{{ form.password|add_error_class:"error-border"|add_required_class:"required-field" }}
35
```
36
37
## Architecture
38
39
Django Widget Tweaks operates through Django's template system using two main approaches:
40
41
- **Template Filters**: Modify form fields by chaining filters that manipulate widget attributes
42
- **Template Tags**: Use HTML-like syntax with the `render_field` tag for more intuitive field customization
43
44
The library works by copying Django BoundField objects and decorating their `as_widget` method to inject custom attributes, ensuring the original form definitions remain unchanged.
45
46
## Capabilities
47
48
### Attribute Manipulation
49
50
Core functionality for setting, appending, and removing HTML attributes on Django form fields.
51
52
```python { .api }
53
# Template filters for attribute manipulation
54
{{ field|attr:"attribute:value" }} # Set or replace HTML attribute
55
{{ field|append_attr:"attribute:value" }} # Append to existing attribute
56
{{ field|remove_attr:"attribute" }} # Remove HTML attribute
57
{{ field|set_data:"key:value" }} # Set HTML5 data attribute (data-key="value")
58
```
59
60
**Usage Examples:**
61
62
```html
63
<!-- Set input type -->
64
{{ form.search|attr:"type:search" }}
65
66
<!-- Add placeholder and set multiple attributes -->
67
{{ form.email|attr:"placeholder:user@example.com"|attr:"autocomplete:email" }}
68
69
<!-- Remove unwanted attributes -->
70
{{ form.field|remove_attr:"readonly" }}
71
72
<!-- Set data attributes for JavaScript -->
73
{{ form.price|set_data:"validation:currency"|set_data:"min:0" }}
74
75
<!-- Append to existing classes or attributes -->
76
{{ form.description|append_attr:"class:large-text"|append_attr:"style:min-height: 100px;" }}
77
```
78
79
### CSS Class Management
80
81
Specialized filters for managing CSS classes with conditional application based on field state.
82
83
```python { .api }
84
# CSS class manipulation filters
85
{{ field|add_class:"css_class" }} # Add CSS class(es)
86
{{ field|add_label_class:"css_class" }} # Add CSS class to field label
87
{{ field|add_error_class:"css_class" }} # Add class only if field has errors
88
{{ field|add_required_class:"css_class" }} # Add class only if field is required
89
{{ field|add_error_attr:"attribute:value" }} # Set attribute only if field has errors
90
```
91
92
**Usage Examples:**
93
94
```html
95
<!-- Basic class addition -->
96
{{ form.username|add_class:"form-control" }}
97
98
<!-- Multiple classes -->
99
{{ form.title|add_class:"form-control large-input highlighted" }}
100
101
<!-- Conditional classes based on field state -->
102
{{ form.email|add_error_class:"is-invalid"|add_required_class:"required" }}
103
104
<!-- Style labels -->
105
{{ form.description|add_label_class:"form-label text-bold" }}
106
107
<!-- Accessibility attributes on errors -->
108
{{ form.password|add_error_attr:"aria-invalid:true" }}
109
```
110
111
### HTML-like Field Rendering
112
113
Template tag providing intuitive HTML-like syntax for field customization with support for both assignment and appending operations.
114
115
```python { .api }
116
# render_field template tag
117
{% render_field field attribute="value" attribute+="append_value" %}
118
```
119
120
**Usage Examples:**
121
122
```html
123
<!-- Basic field rendering with attributes -->
124
{% render_field form.title class="form-control" placeholder="Enter title" %}
125
126
<!-- Append to existing attributes -->
127
{% render_field form.description class+=" large-textarea" rows="8" %}
128
129
<!-- Change input types -->
130
{% render_field form.search type="search" %}
131
{% render_field form.phone type="tel" %}
132
133
<!-- Template variables as values -->
134
{% render_field form.message placeholder=form.message.label %}
135
136
<!-- Vue.js style attributes with double colon -->
137
{% render_field form.status v-bind::class="{active:isActive}" %}
138
139
<!-- Mix of assignment and appending -->
140
{% render_field form.tags class="tag-input" class+=" autocomplete" data-source="/api/tags" %}
141
```
142
143
**Context Variables for render_field:**
144
145
```python { .api }
146
# Special template context variables that affect render_field behavior
147
WIDGET_ERROR_CLASS # CSS class automatically applied to fields with errors
148
WIDGET_REQUIRED_CLASS # CSS class automatically applied to required fields
149
```
150
151
**Context Variable Usage:**
152
153
```html
154
{% with WIDGET_ERROR_CLASS='error-field' WIDGET_REQUIRED_CLASS='required-field' %}
155
{% render_field form.email type="email" class="form-control" %}
156
{% render_field form.password type="password" class="form-control" %}
157
{% render_field form.confirm_password type="password" class="form-control" %}
158
{% endwith %}
159
```
160
161
### Field Introspection
162
163
Utility filters for determining field and widget types, useful for conditional template logic and CSS styling.
164
165
```python { .api }
166
# Field type inspection filters
167
{{ field|field_type }} # Returns field class name in lowercase (e.g., "charfield")
168
{{ field|widget_type }} # Returns widget class name in lowercase (e.g., "textinput")
169
```
170
171
**Usage Examples:**
172
173
```html
174
<!-- Dynamic CSS classes based on field type -->
175
<div class="field {{ field|field_type }} {{ field|widget_type }} {{ field.html_name }}">
176
{{ field }}
177
</div>
178
179
<!-- Conditional logic based on field type -->
180
{% if field|field_type == "charfield" %}
181
{{ field|attr:"maxlength:255" }}
182
{% elif field|field_type == "emailfield" %}
183
{{ field|attr:"type:email" }}
184
{% endif %}
185
186
<!-- Widget-specific styling -->
187
{% if field|widget_type == "textarea" %}
188
{{ field|add_class:"auto-resize" }}
189
{% elif field|widget_type == "select" %}
190
{{ field|add_class:"custom-select" }}
191
{% endif %}
192
```
193
194
## Advanced Usage Patterns
195
196
### Filter Chaining
197
198
Django Widget Tweaks filters can be chained together, with leftmost filters taking precedence (useful for creating reusable templates with overridable defaults):
199
200
```html
201
<!-- Leftmost filter wins -->
202
{{ form.title|attr:"class:default-class"|attr:"class:override-class" }}
203
<!-- Result: class="default-class" -->
204
205
<!-- Reusable field template with defaults -->
206
{# inc/field.html #}
207
{% load widget_tweaks %}
208
<div class="field-wrapper">
209
{{ field|add_class:"form-control"|attr:"data-default:true" }}
210
</div>
211
212
{# Usage with overrides #}
213
{% include "inc/field.html" with field=form.email|attr:"data-default:false"|add_class:"email-field" %}
214
```
215
216
### Mixing render_field with Filters
217
218
The `render_field` tag can be combined with filters for complex field customization:
219
220
```html
221
{% render_field form.category|append_attr:"readonly:readonly" type="text" placeholder="Category" %}
222
```
223
224
### Form Validation Integration
225
226
Leverage Django's form validation states for dynamic styling:
227
228
```html
229
<!-- Comprehensive field with all states -->
230
{{ form.username|add_class:"form-control"|add_error_class:"is-invalid"|add_required_class:"required"|add_error_attr:"aria-describedby:username-error" }}
231
232
{% if form.username.errors %}
233
<div id="username-error" class="invalid-feedback">
234
{{ form.username.errors.0 }}
235
</div>
236
{% endif %}
237
```
238
239
## Package Metadata
240
241
```python { .api }
242
# Package version (available after installation)
243
import widget_tweaks
244
widget_tweaks.__version__ # String version or None if not installed
245
```
246
247
## Limitations
248
249
- **MultiWidgets**: SplitDateTimeWidget and SplitHiddenDateTimeWidget are not supported
250
- **Filter Order**: Filter chaining follows leftmost-wins precedence which may be counter-intuitive
251
- **Field State**: Filters create copies of BoundField objects, so multiple applications may not reflect the most recent state changes