Form related widgets#

class BaseCheckboxInputBlock(checked: bool = False, **kwargs: Any)[source]#

Bases: InputBlock

A block for rendering a bare <input type="checkbox"> element.

Example

from wildewidgets import BaseCheckboxInputBlock

block_unchecked = BaseCheckboxInputBlock(input_name='my-checkbox', value=1)
block_checked = BaseCheckboxInputBlock(
    input_name='my-checkbox',
    value=1,
    checked=True
)
Keyword Arguments:

checked – if True, render the checkbox as checked

class CheckboxInputBlock(label_text: str | None = None, bold: bool | None = None, input_name: str | None = None, value: str | None = None, checked: bool = False, **kwargs: Any)[source]#

Bases: Block

A block for rendering a <input type="checkbox"> element with a label as a Boostrap 5 check.

Example

from wildewidgets import CheckboxInputBlock

block = CheckboxInputBlock(
    label_text='My Checkbox',
    name='my-checkbox',
    value=1
)
Keyword Arguments:
  • label_text – the text to use for the label

  • bold – if True, make the label text be bold

  • input_name – the value of the name attribute

  • value – the value of the value attribute

  • checked – if True, render the checkbox as checked

bold: bool = True#

if True, make the label text be bold

input_name: str | None = None#

The value of the name attribute on the checkbox

label_text: str | None = None#

The text to use for the label for the checkbox

value: str | None = None#

The value of the value attribute on the checkbox

class CrispyFormWidget(*blocks: Any, form: Form | None = None, **kwargs: Any)[source]#

Bases: Block

A widget that displays a Crispy Form widget. This is specifically a Crispy Form widget because it uses the {% crispy %} template tag to render the form.

Note

If the form is present in the template context already, (because your view inserted it for you) you don’t need to supply the form keyword argument – CrispyFormWidget will pick it up automatically.

Example

from wildewidgets import CrispyFormWidget
from myapp.forms import MyCrispyForm

block = CrispyFormWidget(form=MyCrispyForm())
Parameters:

*blocks – Any blocks to add to this widget. These will be rendered in the order they are provided.

Keyword Arguments:
  • form – A crispy form to display. If none is specified, it will be assumed that form is specified elsewhere in the context.

  • **kwargs – Any additional keyword arguments to pass to the parent class.

get_context_data(*args: Any, **kwargs: Any) dict[str, Any][source]#

Update the template context dictionary used when rendering this block.

Parameters:

*args – positional arguments (ignored)

Keyword Arguments:

**kwargs – the current context dictionary

Returns:

The updated context dictionary

block: str = 'wildewidgets-crispy-form-widget'#

The name of this block.

template_name: str = 'wildewidgets/crispy_form_widget.html'#

The Django template to use to render this widget.

class HiddenInputBlock(**kwargs: Any)[source]#

Bases: InputBlock

A block for rendering a <input type="hidden">.

Example

from wildewidgets import HiddenInputBlock

block = HiddenInputBlock(name='my-checkbox', value=1)
class InputBlock(input_type: str | None = None, input_name: str | None = None, value: str | None = None, **kwargs: Any)[source]#

Bases: Block

A block for rendering a simple <input> element.

Example

from wildewidgets import InputBlock

# A simple text input
block = InputBlock(input_type='text', input_name='my-input', value='Hello')
Keyword Arguments:
  • input_type – the value of the type attribute

  • input_name – the value of the name attribute

  • value – the value of the value attribute

empty: bool = True#

If True, this block uses no close tag

tag: str = 'input'#

The name of the HTML element to use as our tag, e.g. div

class LabelBlock(text: str, for_input: str | None = None, bold: bool | None = None, color: str = 'secondary', **kwargs: Any)[source]#

Bases: Block

A <label>

Parameters:

text – the text for the label

Keyword Arguments:
  • bold – if True, make the label text be bold

  • color – the bootstrap/tabler color to assign to the label

  • for_input – the CSS id of the input this describes

bold: bool = True#

If True, make the label text be bold

for_input: str | None = None#

The CSS id of the input this describes

tag: str = 'label'#

The name of the HTML element to use as our tag, e.g. div

class ToggleSwitchInputBlock(**kwargs: Any)[source]#

Bases: CheckboxInputBlock

A block for rendering a <input type="checkbox"> element with a label as a Bootstrap 5 switch.

Example

from wildewidgets import ToggleSwitchInputBlock

block = ToggleSwitchInputBlock(
    label_text='My Checkbox',
    name='my-checkbox',
    value=1
)
class ToggleableManyToManyFieldBlock(instance: Model, field_name: str | None = None, form_class: type[Form] | None = None, form_action: str | None = None, **kwargs: Any)[source]#

Bases: CardWidget

A block that allows you to manage a many-to-many relationship between a model and a related model as a list of toggleable items.

This widget displays all available related objects as toggle switches, with currently selected items checked. It provides interactive features including:

  • A toggle to hide/show unselected items

  • A search box to filter items by name

This is most appropriate for relationships between a model and a lookup table (e.g., categories, tags, classifiers, etc.) where the related model has a reasonable number of instances.

Important

This block is designed to be used with a model that has a many-to-many relationship with another model. The field_name must be set to the name of the many-to-many field on the model instance. The block will render a form that allows the user to select or deselect related objects.

Also, this block requires that your model has a verbose_name_plural method defined in its Meta class.

We strongly recommend that you use the wildewidgets.ViewSetMixin mixin in your model to provide the required attributes and methods for this block to work correctly.

Example

from wildewidgets import ToggleableManyToManyFieldBlock
from myapp.models import Article

article = Article.objects.get(pk=1)  # Has many-to-many with 'tags'
tags_widget = ToggleableManyToManyFieldBlock(
    instance=article,
    field_name='tags'
)
Parameters:

instance – The model instance that has the many-to-many relationship

Keyword Arguments:
  • field_name – Name of the many-to-many field on the model instance

  • form_class – Custom form class to use (must extend ``ToggleableManyToManyFieldForm)

  • form_action – URL for form submission (if not provided, will be auto-generated)

form_class#

The form class to instantiate to handle our multiple select

alias of ToggleableManyToManyFieldForm

get_form(instance: Model, field_name: str, form_action: str) Form[source]#

Create and return a form for managing many-to-many relationships.

This method instantiates a form of the class specified by the form_class attribute, binding it to the specified instance, field name, and form action. The form will be used to manage the many-to-many relationship between the instance and related model objects.

Parameters:
  • instance – The model instance to which the form will be bound

  • field_name – The name of the many-to-many field on the model

  • form_action – The URL to which the form will be submitted

Returns:

An initialized form instance ready to be rendered

Return type:

Form

get_header() Block[source]#

Get our card header. This consists of a toggle switch which hides/shows unselected items and a search input that allows the user to search for items.

Returns:

The card header block.

classmethod get_url_name() str[source]#

Generate a standardized URL name for this widget’s form submission endpoint.

This method constructs a URL name by combining the model name and related model name in a standardized format. The URL name is used for routing form submissions to the appropriate view and follows the pattern: “{model_name}–{related_model_name}–update”

The model names are converted to lowercase with underscores using the model_logger_name utility function.

Returns:

A URL name in the format “{model_name}–{related_model_name}–update”

Return type:

str

Raises:
  • ValueError – If the model or field_name class attributes are not defined

  • AssertionError – If the related_model is None

Note

This method requires that both the model and field_name class attributes are defined before calling.

classmethod get_urlpatterns(url_prefix: str | None = None, url_namespace: str | None = None) list[django.urls.resolvers.URLPattern][source]#

Build a view that will service this block and return a django.urls.URLPattern for that view that you can add to your urlpatterns.

Example:

from typing import List
from django.urls import path, URLPattern

from wildewidgets import ToggleableManyToManyFieldBlock

from .views import HomeView
from .models import MyModel

class TagsSelectorWidget(ToggleableManyToManyFieldBlock):

    model = MyModel
    field_name = 'tags'

app_name: str = "myapp"

urlpatterns: List[URLPattern] = [
    path('', HomeView.as_view(), name='home'),
]
urlpatterns += TagsSelectorWidget.get_urlpatterns(url_namespace=app_name)

Important

In order for this to work, you must have subclassed ToggleableManyToManyFieldBlock and defined both the model and field_name attributes.

Keyword Arguments:
  • url_prefix – a prefix to the path we will build for our view

  • url_namespace – the namespace for our url pattern. We’ll set our url_namespace from this

Returns:

A list of urlpatterns for a view suitable for this block

SCRIPT: Final[str] = '\ndocument.querySelectorAll("{target} input.form-check-input").forEach(input => {{\n    if (!input.checked) {{\n        input.parentElement.classList.add(\'d-none\');\n    }};\n}});\nvar show_input = document.getElementById("{show_unselected_id}");\nshow_input.onchange = function(e) {{\n    document.querySelectorAll("{target} input.form-check-input").forEach(input => {{\n        if (show_input.checked && !input.checked) {{\n            input.parentElement.classList.add(\'d-none\');\n        }} else {{\n            input.parentElement.classList.remove(\'d-none\');\n        }};\n    }});\n}};\nvar filter_input = document.getElementById("{filter_id}");\nfilter_input.onkeyup = function(e) {{\n    var filter = filter_input.value.toLowerCase();\n    show_input.checked = false\n    document.querySelectorAll("{target} label").forEach(label => {{\n        var test_string = label.innerText.toLowerCase();\n        if (test_string.includes(filter)) {{\n            label.parentElement.classList.remove(\'d-none\');\n        }} else {{\n            label.parentElement.classList.add(\'d-none\');\n        }}\n    }});\n}};\n'#

The JavaScript to run to hide unselected items and filter the list of items. The {target} placeholder will be replaced with the CSS id of the form that this block will render. The {filter_id} placeholder will be replaced with the CSS id of the filter input. The {show_unselected_id} placeholder will be replaced with the CSS id of the “Hide unselected” toggle switch. The JavaScript will hide all unselected items on page load, and will toggle the visibility of unselected items when the “Hide unselected” toggle is clicked. It will also filter the list of items based on the text in the filter input.

field_name: str | None = None#

The name of the related field on our model instance for which we want to build this widget

property filter_id: str#

Generate a unique CSS ID for the filter input element.

This property appends “_filter” to the form_id to create a unique identifier for the search input field used to filter the list of items.

Returns:

A string in the format of “modelname_fieldname_filter”

Return type:

str

form_action: str | None = None#

The URL to which to POST this form

property form_id: str#

Generate a unique CSS ID for the form element.

This property creates a standardized ID by combining the model’s object name with the field name. This ID is used for DOM selection in JavaScript and for linking form elements.

Returns:

A string in the format of “modelname_fieldname”

Return type:

str

Raises:

AssertionError – If the model is not defined

model: type[Model] | None = None#

The model this widget will be used with. This is only used by our as_v

name: str = 'toggle-form-block'#

The name of this block.

property show_all_switch_id: str#

Generate a unique CSS ID for the “show all” toggle switch.

This property appends “_show_all” to the form_id to create a unique identifier for the toggle switch that controls the visibility of unselected items.

Returns:

A string in the format of “modelname_fieldname_show_all”

Return type:

str

url_namespace: str | None = None#

The URL namespace to use for our view name. This should be set to the app_name set in the urls.py where this viewset’s patterns will be added to urlpatterns.

url_prefix: str = ''#

The path prefix to use to root view.