or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.md
tile.json

tessl/pypi-django-widget-tweaks

Django template tags and filters for customizing form field rendering without modifying Python form definitions.

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
pypipkg:pypi/django-widget-tweaks@1.5.x

To install, run

npx @tessl/cli install tessl/pypi-django-widget-tweaks@1.5.0

index.mddocs/

Django Widget Tweaks

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.

Package Information

  • Package Name: django-widget-tweaks
  • Package Type: pypi
  • Language: Python
  • Installation: pip install django-widget-tweaks
  • Django Setup: Add 'widget_tweaks' to INSTALLED_APPS in settings.py

Core Imports

# Load in Django templates
{% load widget_tweaks %}

Basic Usage

{% load widget_tweaks %}

<!-- Basic attribute modification -->
{{ form.name|attr:"placeholder:Enter your name" }}

<!-- Add CSS classes -->
{{ form.email|add_class:"form-control email-input" }}

<!-- Use render_field tag for HTML-like syntax -->
{% render_field form.message rows="5" cols="40" placeholder="Your message" %}

<!-- Conditional styling based on field state -->
{{ form.password|add_error_class:"error-border"|add_required_class:"required-field" }}

Architecture

Django Widget Tweaks operates through Django's template system using two main approaches:

  • Template Filters: Modify form fields by chaining filters that manipulate widget attributes
  • Template Tags: Use HTML-like syntax with the render_field tag for more intuitive field customization

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.

Capabilities

Attribute Manipulation

Core functionality for setting, appending, and removing HTML attributes on Django form fields.

# Template filters for attribute manipulation
{{ field|attr:"attribute:value" }}  # Set or replace HTML attribute
{{ field|append_attr:"attribute:value" }}  # Append to existing attribute
{{ field|remove_attr:"attribute" }}  # Remove HTML attribute
{{ field|set_data:"key:value" }}  # Set HTML5 data attribute (data-key="value")

Usage Examples:

<!-- Set input type -->
{{ form.search|attr:"type:search" }}

<!-- Add placeholder and set multiple attributes -->
{{ form.email|attr:"placeholder:user@example.com"|attr:"autocomplete:email" }}

<!-- Remove unwanted attributes -->  
{{ form.field|remove_attr:"readonly" }}

<!-- Set data attributes for JavaScript -->
{{ form.price|set_data:"validation:currency"|set_data:"min:0" }}

<!-- Append to existing classes or attributes -->
{{ form.description|append_attr:"class:large-text"|append_attr:"style:min-height: 100px;" }}

CSS Class Management

Specialized filters for managing CSS classes with conditional application based on field state.

# CSS class manipulation filters
{{ field|add_class:"css_class" }}  # Add CSS class(es)
{{ field|add_label_class:"css_class" }}  # Add CSS class to field label
{{ field|add_error_class:"css_class" }}  # Add class only if field has errors
{{ field|add_required_class:"css_class" }}  # Add class only if field is required
{{ field|add_error_attr:"attribute:value" }}  # Set attribute only if field has errors

Usage Examples:

<!-- Basic class addition -->
{{ form.username|add_class:"form-control" }}

<!-- Multiple classes -->
{{ form.title|add_class:"form-control large-input highlighted" }}

<!-- Conditional classes based on field state -->
{{ form.email|add_error_class:"is-invalid"|add_required_class:"required" }}

<!-- Style labels -->
{{ form.description|add_label_class:"form-label text-bold" }}

<!-- Accessibility attributes on errors -->
{{ form.password|add_error_attr:"aria-invalid:true" }}

HTML-like Field Rendering

Template tag providing intuitive HTML-like syntax for field customization with support for both assignment and appending operations.

# render_field template tag  
{% render_field field attribute="value" attribute+="append_value" %}

Usage Examples:

<!-- Basic field rendering with attributes -->
{% render_field form.title class="form-control" placeholder="Enter title" %}

<!-- Append to existing attributes -->
{% render_field form.description class+=" large-textarea" rows="8" %}

<!-- Change input types -->
{% render_field form.search type="search" %}
{% render_field form.phone type="tel" %}

<!-- Template variables as values -->
{% render_field form.message placeholder=form.message.label %}

<!-- Vue.js style attributes with double colon -->
{% render_field form.status v-bind::class="{active:isActive}" %}

<!-- Mix of assignment and appending -->
{% render_field form.tags class="tag-input" class+=" autocomplete" data-source="/api/tags" %}

Context Variables for render_field:

# Special template context variables that affect render_field behavior
WIDGET_ERROR_CLASS  # CSS class automatically applied to fields with errors  
WIDGET_REQUIRED_CLASS  # CSS class automatically applied to required fields

Context Variable Usage:

{% with WIDGET_ERROR_CLASS='error-field' WIDGET_REQUIRED_CLASS='required-field' %}
    {% render_field form.email type="email" class="form-control" %}
    {% render_field form.password type="password" class="form-control" %}  
    {% render_field form.confirm_password type="password" class="form-control" %}
{% endwith %}

Field Introspection

Utility filters for determining field and widget types, useful for conditional template logic and CSS styling.

# Field type inspection filters
{{ field|field_type }}  # Returns field class name in lowercase (e.g., "charfield")
{{ field|widget_type }}  # Returns widget class name in lowercase (e.g., "textinput")

Usage Examples:

<!-- Dynamic CSS classes based on field type -->
<div class="field {{ field|field_type }} {{ field|widget_type }} {{ field.html_name }}">
    {{ field }}
</div>

<!-- Conditional logic based on field type -->
{% if field|field_type == "charfield" %}
    {{ field|attr:"maxlength:255" }}
{% elif field|field_type == "emailfield" %}
    {{ field|attr:"type:email" }}
{% endif %}

<!-- Widget-specific styling -->
{% if field|widget_type == "textarea" %}
    {{ field|add_class:"auto-resize" }}
{% elif field|widget_type == "select" %}
    {{ field|add_class:"custom-select" }}
{% endif %}

Advanced Usage Patterns

Filter Chaining

Django Widget Tweaks filters can be chained together, with leftmost filters taking precedence (useful for creating reusable templates with overridable defaults):

<!-- Leftmost filter wins -->
{{ form.title|attr:"class:default-class"|attr:"class:override-class" }}
<!-- Result: class="default-class" -->

<!-- Reusable field template with defaults -->
{# inc/field.html #}
{% load widget_tweaks %}
<div class="field-wrapper">
    {{ field|add_class:"form-control"|attr:"data-default:true" }}
</div>

{# Usage with overrides #}
{% include "inc/field.html" with field=form.email|attr:"data-default:false"|add_class:"email-field" %}

Mixing render_field with Filters

The render_field tag can be combined with filters for complex field customization:

{% render_field form.category|append_attr:"readonly:readonly" type="text" placeholder="Category" %}

Form Validation Integration

Leverage Django's form validation states for dynamic styling:

<!-- Comprehensive field with all states -->
{{ form.username|add_class:"form-control"|add_error_class:"is-invalid"|add_required_class:"required"|add_error_attr:"aria-describedby:username-error" }}

{% if form.username.errors %}
    <div id="username-error" class="invalid-feedback">
        {{ form.username.errors.0 }}
    </div>
{% endif %}

Package Metadata

# Package version (available after installation)
import widget_tweaks
widget_tweaks.__version__  # String version or None if not installed

Limitations

  • MultiWidgets: SplitDateTimeWidget and SplitHiddenDateTimeWidget are not supported
  • Filter Order: Filter chaining follows leftmost-wins precedence which may be counter-intuitive
  • Field State: Filters create copies of BoundField objects, so multiple applications may not reflect the most recent state changes