Table Widgets#

Tables#

class StaticTableRowWidget(cells: list[str | wildewidgets.widgets.base.Block], cell_tag: str | None = None, cell_css_class: str | None = None, **kwargs)[source]#

Bases: Block

Simple static table row widget. This widget is used to create a row in a StaticTableWidget.

Parameters:
  • cells – the cells to add to the row

  • cell_tag – the HTML tag for the cells

  • cell_css_class – the CSS class for the cells

  • **kwargs – additional keyword arguments to pass to the block

cell_tag: str = 'td'#

The HTML tag for the cells

tag: str = 'tr'#

The HTML tag for the row

class StaticTableWidget(headings: list[str | wildewidgets.widgets.base.Block] | None = None, rows: list[list[str | wildewidgets.widgets.base.Block]] | None = None, cell_css_class: str | None = None, **kwargs)[source]#

Bases: Block

Simple static table widget. This differs from the DataTable type widgets in that it does not use dataTables.js and is therefore simpler for small lists of data.

It offers a sorting mechanism by clicking on the “Sort” button in the heading of the column. The table is sorted by the text content of the cells in the column that the button is in. If every cell in that column is numeric (optional minus, digits, optional decimal), the column is sorted numerically; otherwise locale-aware alphabetical sort is used. Empty cells in numeric columns sort last (ascending) or first (descending).

Examples

With constructor arguments:

from wildewidgets import StaticTableWidget

table = StaticTableWidget(
    headings=["Name", "Age", "City"],
    rows=[["John", 25, "New York"], ["Jane", 30, "Los Angeles"]]
)

print(table)

With constructor overrides:

from wildewidgets import StaticTableWidget

class MyStaticTableWidget(StaticTableWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.add_heading("Name")
        self.add_heading("Age")
        self.add_heading("City")
        self.add_row(["John", 25, "New York"])
        self.add_row(["Jane", 30, "Los Angeles"])

table = MyStaticTableWidget()
print(table)

With method calls:

from wildewidgets import StaticTableWidget

table = StaticTableWidget()
table.add_heading("Name")
table.add_heading("Age")
table.add_heading("City")
table.add_row(["John", 25, "New York"])
table.add_row(["Jane", 30, "Los Angeles"])

print(table)
from wildewidgets import StaticTableWidget
table = StaticTableWidget(
    headings=["Name", "Age", "City"],
    rows=[["John", 25, "New York"], ["Jane", 30, "Los Angeles"]]
)
table.add_heading("Country")
table.add_heading("Occupation")
table.add_heading("City"sjj
table.add_row(
     ["John", 25, "New York", "United States", "Software Engineer"]
)
table.add_row(
    ["Jane", 30, "Los Angeles", "United States", "Software Engineer"]
)

print(table)
Keyword Arguments:
  • headings – the headings for the table

  • rows – the rows for the table

  • cell_css_class – the CSS class for the cells

  • **kwargs – additional keyword arguments to pass to the block

add_heading(heading: str | wildewidgets.widgets.base.Block) None[source]#

Add a single heading to the table. Do this before adding any rows.

Parameters:

heading – the heading to add to the table

add_row(row: list[str | wildewidgets.widgets.base.Block]) None[source]#

Add a single row to the table. Do this after adding headings.

name: str = 'static-table'#

The HTML name for the widget for CSS styling and JavaScript

property script: str#

A JavaScript script to sort the table by clicking on a button in the headings.

Iniitially, the table is sorted in the order they are listed in the data source.

It draws a button in the <th> elements named “Sort” with the current sort order represented by an arrow (if we are sorting) or a blank (if we are not sorting). When the button is clicked, the table is sorted by the opposite of the current sort order or ascending (if no sort order is set), and the button text is updated to the opposite of the selected sort order.

Note

The table is sorted by the text content of the cells in the column that the button is in. If every cell in that column is numeric (optional minus, digits, optional decimal), the column is sorted numerically; otherwise locale-aware alphabetical sort is used. Empty cells in numeric columns sort last (ascending) or first (descending).

Parameters:

self – the widget instance

Returns:

A string of JavaScript code to sort the table by clicking on the headings.

tag: str = 'table'#

The HTML tag for the table

class ActionButtonModelTable(*args, actions: list[wildewidgets.widgets.tables.actions.RowActionButton] | None = None, button_size: str | None = None, justify: Optional[Literal['start', 'center', 'end']] = None, **kwargs)[source]#

Bases: ActionButtonBlockMixin, ModelTableMixin, BaseDataTable

Model table with customizable row action buttons.

This class allows you to define action buttons for each row using RowActionButton instances and subclasses, providing flexibility in button appearance and behavior. Buttons can perform different actions based on the row data, like linking to detail pages, opening modals, or submitting forms.

Example

from django.db import models
from wildewidgets import (
    ActionButtonModelTable,
    RowModelUrlButton,
    RowFormButton
)

class Author(models.Model):
    full_name = models.CharField(max_length=100)

class Book(models.Model):
    title = models.CharField(max_length=200)
    authors = models.ManyToManyField(Author, related_name='books')
    isbn = models.CharField(max_length=20)

    def get_absolute_url(self):
        return f"/books/{self.id}/"

    def get_delete_url(self):
        return f"/books/{self.id}/delete/"

class BookTable(ActionButtonModelTable):
    model = Book
    fields = ['title', 'authors__full_name', 'isbn']
    verbose_names = {'authors__full_name': 'Authors'}

    actions = [
        RowModelUrlButton(
            text='View',
            color='primary',
            attribute='get_absolute_url'
        ),
        RowFormButton(
            text='Delete',
            color='danger',
            attribute='get_delete_url',
            form_fields=['id'],
            confirm_text='Are you sure you want to delete this book?'
        )
    ]
class BasicModelTable(*args, model: type[django.db.models.base.Model] | None = None, fields: str | list[str] | None = None, hidden: list[str] | None = None, verbose_names: dict[str, str] | None = None, unsortable: list[str] | None = None, unsearchable: list[str] | None = None, field_types: dict[str, str] | None = None, alignment: dict[str, Literal['left', 'right', 'center']] | None = None, bool_icons: dict[str, tuple[tuple[str, str], ...]] | None = None, **kwargs)[source]#

Bases: ModelTableMixin, DataTable

Ready-to-use table for displaying Django model data.

This class combines ModelTableMixin and DataTable to provide a complete solution for displaying model data with minimal configuration. Simply define your model and field configuration as class attributes.

Example

from django.db import models
from wildewidgets.widgets.tables import BasicModelTable

class Author(models.Model):
    full_name = models.CharField(max_length=100)

class Book(models.Model):
    title = models.CharField(max_length=200)
    authors = models.ManyToManyField(Author, related_name='books')
    isbn = models.CharField(max_length=20)

# Example table using BasicModelTable

class BookTable(BasicModelTable):
    model = Book
    fields = ['title', 'authors__full_name', 'isbn']
    alignment = {'authors': 'left'}
    verbose_names = {'authors__full_name': 'Authors'}
    buttons = True
    striped = True

    def render_authors__full_name_column(self, row, column):
        authors = row.authors.all()
        if authors.count() > 1:
            return f"{authors[0].full_name} + {authors.count()-1} more"
        return authors[0].full_name if authors else ""
class DataTable(*args, actions: Any = None, action_button_size: str | None = None, default_action_button_label: str | None = None, default_action_button_color_class: str | None = None, **kwargs)[source]#

Bases: ActionsButtonsBySpecMixin, BaseDataTable

Standard data table implementation with action buttons specs.

This class combines BaseDataTable with wildewidgets.ActionsButtonsBySpecMixin to create a complete table implementation that supports all base table features plus action buttons for each row.

Example

from wildewidgets.widgets.tables import DataTable

class MyTable(DataTable):
    actions = [
        ('Edit', 'my_app:edit'),
        ('Delete', 'my_app:delete', 'post', 'danger')
    ]

    def get_queryset(self):
        return MyModel.objects.all()
class LookupModelTable(*args, **kwargs)[source]#

Bases: ActionButtonBlockMixin, ModelTableMixin, BaseDataTable

Specialized table for lookup/reference data with automatic field discovery. This is used by the wildewidgets.ModelViewSet to display reference data like categories, statuses, or other lookup tables.

This table is designed for displaying reference/lookup tables and automatically configures itself to:

  1. Show only direct model fields (no related fields)

  2. Left-align the ID column for better readability

  3. Support row actions via wildewidgets.ActionButtonBlockMixin

This table is ideal for admin interfaces or data management views for reference data like categories, statuses, or other lookup tables.

Requirements:
  • Your model must implement get_absolute_url, get_update_url and get_delete_url methods

Note

If fields are not specified, the table automatically includes all non-relation fields from the model.

Example

from django.db import models
from wildewidgets.widgets.tables import LookupModelTable

class Category(models.Model):
    name = models.CharField(max_length=100)
    description = models.TextField(blank=True, null=True)

    def get_absolute_url(self):
        return f"/categories/{self.id}/"

    def get_update_url(self):
        return f"/categories/{self.id}/edit/"

    def get_delete_url(self):
        return f"/categories/{self.id}/delete/"

class CategoryTable(LookupModelTable):
    model = Category
Keyword Arguments:
  • fields – A list of field names to include in the table. If not provided, defaults to all non-relation fields on the model.

  • model – The Django model class to use for this table. If not provided, the model attribute must be set on the class.

Raises:

ImproperlyConfigured – If the model is not set as either a class attribute or provided during initialization.

actions: list[RowActionButton] = []#

A list of RowActionButton subclasses to display in the “Actions” column.

class ModelTableMixin(*args, model: type[django.db.models.base.Model] | None = None, fields: str | list[str] | None = None, hidden: list[str] | None = None, verbose_names: dict[str, str] | None = None, unsortable: list[str] | None = None, unsearchable: list[str] | None = None, field_types: dict[str, str] | None = None, alignment: dict[str, Literal['left', 'right', 'center']] | None = None, bool_icons: dict[str, tuple[tuple[str, str], ...]] | None = None, **kwargs)[source]#

Bases: object

Mixin used to create a table from a Django Model with automatic column configuration.

This mixin automatically discovers model fields and creates appropriate table columns with sensible defaults for alignment, sorting, and display formatting. It handles both direct model fields and related fields through Django’s double-underscore notation.

Important

Typically you will not use this directly in your code, but instead use one of the pre-defined table classes like BasicModelTable, ActionButtonModelTable, or StandardActionButtonModelTable.

Notes

  • Django DateField and DateTimeField fields are automatically formatted using the WILDEWIDGETS_DATE_FORMAT and `` WILDEWIDGETS_DATETIME_FORMAT`` settings.

  • Django BooleanField fields can be rendered with custom icons using the bool_icons attribute, which maps field names to tuples of icon specifications.

  • For the field_types attribute/kwarg, currently available choices for the dict values are:

    • date: For formatting date fields

    • datetime: For formatting datetime fields

    • currency: For formatting currency values with a dollar sign

    • bool: For rendering boolean values as check icons

  • You may add a new field type by implementing a method named render_FIELD_type_column on your table class, where FIELD is the name of the field type (e.g., render_currency_type_column)

Example

from django.db import models
from django.contrib.contenttypes.fields import GenericForeignKey
from wildewidgets.widgets.tables import ModelTableMixin, DataTable

class Author(models.Model):
    full_name = models.CharField(max_length=100)

class Book(models.Model):
    title = models.CharField(max_length=200)
    authors = models.ManyToManyField(Author, related_name='books')
    isbn = models.CharField(max_length=20)
    published_date = models.DateField()

# Example table using ModelTableMixin

class BookTable(ModelTableMixin, DataTable):
    model = Book
    fields = ['title', 'authors__full_name', 'isbn', 'published_date']
    alignment = {'isbn': 'center', 'published_date': 'right'}
    verbose_names = {'authors__full_name': 'Authors'}
    field_types = {'published_date': 'date'}

    def render_authors__full_name_column(self, row, column):
        return ", ".join([a.full_name for a in row.authors.all()])
Parameters:

*args – Variable length argument list (unused)

Keyword Arguments:
  • model – The Django model class to use for this table. If not provided, the model attribute must be set on the class.

  • fields – A list of field names to include in the table. If not provided, defaults to all fields on the model. The fields attribute can be set to None, an empty list, or the string “__all__” to include all fields on the model. If a list is provided, it can include related fields using Django’s double-underscore notation (e.g., authors__full_name).

  • hidden – A list of field names to hide by default. Users can unhide fields via the table controls.

  • verbose_names – A dictionary mapping field names to custom column headers where the key is the field name and the value is the desired header text.

  • unsortable – A list of field names that will not be sortable. This means that the up/down arrows will not be displayed in the table header for these fields, and they will not be included in the sort query.

  • unsearchable – A list of field names that will not be searched when doing a global table search. This means the field will not be included in the search query, but it will still be displayed in the table.

  • field_types – A dictionary mapping field names to data types for automatic formatting of table values.

  • alignment – A dictionary mapping field names to alignment values. Valid values are left, right, and center. The key is the field name and the value is the alignment value. If not provided, defaults to left for all text fields and right for numeric fields.

  • bool_icons – A dictionary mapping field names to tuples of icon specifications for rendering boolean values. Each tuple should contain 1-2 icon specs: (icon_name, css_class) for True and optionally (icon_name, css_class) for False.

Raises:
  • ImproperlyConfigured – If the model is not set and no model is provided during initialization.

  • django.core.exceptions.FieldDoesNotExist – If a specified field does not exist on the model or related models.

get_field(field_name: str) models.Field | models.ForeignObjectRel | GenericForeignKey | None[source]#

Get a field instance by name, checking both direct and related fields.

Parameters:

field_name – The name of the field to retrieve

Returns:

The Django Field instance or None if not found

Resolve a field from a related model using Django’s double-underscore notation.

This method handles field paths like ‘author__publisher__name’ by traversing the model relationships to find the final field object.

Parameters:
  • current_model – The starting model class

  • name – Field path using Django’s double-underscore notation

Returns:

The Django Field instance for the final field in the path, or None if not found

Example

For a path ‘author__publisher__name’, this would:

  1. Get the ‘author’ field from the current model

  2. Get the related model (Publisher)

  3. Return the ‘name’ field from the Publisher model

Get the related model for a relationship field.

Parameters:
  • current_model – The model containing the relationship field

  • field_name – The name of the relationship field

Returns:

The related model class or None if not found

load_all_fields() None[source]#

Add columns for all discovered model fields to the table.

This is called when fields=”__all__” or when fields is empty.

load_field(field_name: str) None[source]#

Add a column for a single field to the table.

This method handles field discovery, verbose name resolution, and column attribute configuration before adding the column to the table.

Parameters:

field_name – The name of the field to add as a column

render_bool_icon_column(value: Any, icon_data: tuple[tuple[str, str], ...]) str[source]#

Format a boolean value using custom icons.

Parameters:
  • value – The boolean value to format

  • icon_data – Tuple of icon specifications (icon_name, css_class)

Returns:

HTML for the specified icon based on the boolean value

Note

The icon_data tuple should contain 1-2 icon specifications: - First icon is used for True values - Second icon (if provided) is used for False values

render_bool_type_column(value: Any) str[source]#

Format a boolean value as a check icon for True values.

Parameters:

value – The boolean value to format

Returns:

HTML for a checkmark icon if True, empty string if False

render_column(row: Any, column: str) str[source]#

Render a cell value with appropriate formatting based on field type.

This method handles special formatting for different field types:

  • Applies custom rendering for fields in field_types dictionary

  • Automatically formats DateTimeField and DateField values

  • Applies icon rendering for boolean fields in bool_icons dictionary

Parameters:
  • row – The data object for the current row

  • column – The name of the column to render

Returns:

Formatted HTML string for the cell value

render_currency_type_column(value: Any) str[source]#

Format a value as currency with a dollar sign.

Parameters:

value – The value to format

Returns:

Formatted currency string with dollar sign

render_date_type_column(value: datetime.date) str[source]#

Format a date value with the configured date format.

Parameters:

value – The date value to format

Returns:

Formatted date string, optionally with title attribute for full date format

Note

The format can be customized using the WILDEWIDGETS_DATE_FORMAT setting in Django settings.

render_datetime_type_column(value: datetime.datetime) str[source]#

Format a datetime value with the configured datetime format.

Parameters:

value – The datetime value to format

Returns:

Formatted datetime string

Note

The format can be customized using the WILDEWIDGETS_DATETIME_FORMAT setting in Django settings.

set_standard_column_attributes(field_name: str, kwargs: dict[str, Any]) None[source]#

Set standard column attributes based on field type and configuration.

This method configures:

  • Visibility based on the ‘hidden’ list

  • Searchability based on the ‘unsearchable’ list

  • Sortability based on the ‘unsortable’ list

  • Alignment based on the ‘alignment’ dict or field type

Parameters:
  • field_name – The name of the field to configure

  • kwargs – Dictionary of attributes to update

alignment: dict[str, Literal['left', 'right', 'center']] = {}#

A mapping of field name to field alignment. Valid values are left, right, and : center

field_names: list[str]#

A list of names of our model fields

field_types: dict[str, str] = {}#

A mapping of field name to data type. This is used to do some automatic formatting of table values.

fields: str | list[str] | None = []#

This is either None, the string __all__ or a list of column names to use in our table. For the list, entries can either be field names from our model, or names of computed fields that will be rendered with a render_FIELD_column method. If None, empty list or __all__, display all fields on the model.

hidden: list[str] = []#

The list of field names to hide by default

model: type[models.Model] | None = None#

The Django model class for this table

model_fields: dict[str, models.Field | models.ForeignObjectRel | GenericForeignKey]#

A mapping of field name to Django field class

related_fields: dict[str, models.Field | models.ForeignObjectRel | GenericForeignKey]#

A mapping of field name to Django related field class

unsearchable: list[str] = []#

A list of field names that will not be searched when doing a global table search

unsortable: list[str] = []#

A list of field names that will not be sortable

verbose_names: dict[str, str] = {}#

A mapping of field name to table column heading

class StandardActionButtonModelTable(*args, actions: list[wildewidgets.widgets.tables.actions.RowActionButton] | None = None, button_size: str | None = None, justify: Optional[Literal['start', 'center', 'end']] = None, **kwargs)[source]#

Bases: ActionButtonBlockMixin, ModelTableMixin, BaseDataTable

Model table with standard “Edit” and “Delete” buttons for each row.

This class provides a convenient implementation for the common pattern of displaying model data with “Edit” and “Delete” actions. It automatically creates these buttons and links them to the appropriate URLs from your model.

Requirements:
  • Your model must have the wildewidgets.ViewSetMixin mixin in its inheritance chain

  • Your model must implement get_absolute_url, get_update_url and get_delete_url methods

model#

The Django model class to display

fields#

List of fields to include in the table

Example

from django.db import models
from django.urls import reverse
from wildewidgets.models import ViewSetMixin

class Book(ViewSetMixin, models.Model):
    title = models.CharField('Title', max_length=100)
    isbn = models.CharField('ISBN', max_length=20)

    def get_absolute_url(self):
        return reverse('books:detail', args=[self.id])

    def get_update_url(self):
        return reverse('books:edit', args=[self.id])

    def get_delete_url(self):
        return reverse('books:delete', args=[self.id])

class BookTable(StandardActionButtonModelTable):
    model = Book
    fields = ['title', 'isbn']
class WidgetCellMixin[source]#

Bases: object

Mixin that enables using custom widgets to render individual table cells.

This mixin allows you to specify custom widget classes for different columns, providing complete control over how cell data is rendered. Each widget receives the row data and column name, allowing for complex rendering based on the full context of the data.

If a widget is defined for a column in the cell_widgets dictionary, it will be used to render the cell. Otherwise, the standard column rendering will be used.

Important

Cell widgets need to be wildewidgets.Block subclasses that accept two additional keyword arguments:

  • row: The data object for the current row

  • column: The name of the column to render

from wildewidgets import Block

class MyCellWidget(Block):

    def __init__(self, row=None, column=None, **kwargs):
        self.row = row
        self.column = column
        self.value = getattr(row, column)
        super().__init__(f"Value is {self.value}", **kwargs)
cell_widgets#

Dictionary mapping column names to widget classes for rendering cells in those columns

Type:

dict[str, type[Widget]]

Example

from wildewidgets import WidgetCellMixin, DataTable
from wildewidgets.widgets.base import Block

class StatusWidget(Block):
    def __init__(self, row=None, column=None, **kwargs):
        super().__init__(**kwargs)
        status = getattr(row, column)
        if status == 'active':
            self.add_class('badge bg-success')
        elif status == 'pending':
            self.add_class('badge bg-warning')
        else:
            self.add_class('badge bg-secondary')
        self.text = status.capitalize()

class MyTable(WidgetCellMixin, DataTable):
    cell_widgets = {
        'status': StatusWidget
    }
render_column(row: Any, column: str) str[source]#

Render a cell using a custom widget if defined for the column.

If a widget is defined for the column in cell_widgets, this method instantiates the widget with the row and column data and returns its rendered output. Otherwise, it falls back to the standard column rendering.

Parameters:
  • row – The data object for the current row

  • column – The name of the column to render

Returns:

Rendered HTML string for the cell

cell_widgets: dict[str, type[Widget]] = {}#

Specify the widget to use for each column. The key is the column name and the value is the widget class. The widget class must be a subclass of wildewidgets.Block. Fields that are not specified will not have a widget, but will be displayed as text.

Components#

class DataTableColumn(field: str, verbose_name: str | None = None, searchable: bool = False, sortable: bool = False, align: str = 'left', head_align: str = 'left', visible: bool = True, wrap: bool = True)[source]#

Bases: object

Defines a column configuration for a wildewidgets.DataTable.

This class stores the configuration for a single column in a DataTable, including display options, behavior, and formatting settings.

Example

from wildewidgets import DataTableColumn

# Create a right-aligned numeric column that can be sorted
column = DataTableColumn(
    field="amount",
    verbose_name="Amount ($)",
    searchable=True,
    sortable=True,
    align="right"
)
Parameters:

field – Field name or identifier for the column

Keyword Arguments:
  • verbose_name – Human-readable name for the column header (defaults to capitalized field name)

  • searchable – Whether this column is included in global searches

  • sortable – Whether the table can be sorted by this column

  • align – Horizontal alignment of cell content (“left”, “right”, “center”)

  • head_align – Horizontal alignment of the column header (“left”, “right”, “center”)

  • visible – Whether the column is visible in the table

  • wrap – Whether to wrap text content in the column cells

class DataTableFilter(header: Any | None = None)[source]#

Bases: object

Defines a filter control for a wildewidgets.DataTable column.

This class represents a UI control for filtering data in a specific column, typically displayed as a dropdown list of options.If no default is provided, the filter is off by default.

Example

from wildewidgets import DataTableFilter

# Create a status filter with custom options
filter = DataTableFilter(
    header="Filter by Status",
)
filter.add_choice("Active", "active")
filter.add_choice("Inactive", "inactive")
filter.add_choice("Pending", "pending")

# Add the filter to the table
table.add_filter("status", filter)
Keyword Arguments:

header – Optional header content for the filter

add_choice(label: str, value: str, default: bool = False) None[source]#

Add a filter option to the choices list.

Parameters:
  • label – The human-readable label displayed in the UI

  • value – The value used for filtering when this option is selected

  • default – Whether this option is the default selected option

class DataTableForm(table: Any)[source]#

Bases: object

Provides form handling for bulk actions in a DataTable.

This class integrates form functionality into a DataTable, allowing users to select multiple rows using checkboxes and perform actions on the selected rows, such as delete, approve, or export.

Note

This class is created automatically by the wildewidgets.DataTable or its subclasses when wildewidgets.DataTable.form_actions are defined.

You typically do not need to instantiate this class directly.

The form is only visible if the table has wildewidgets.DataTable.form_actions defined. Form actions and URL are retrieved from the table instance.

Parameters:

table – The DataTable instance this form belongs to

class DataTableStyler(is_row: bool, test_cell: str, cell_value: Any, css_class: str, target_cell: str | None = None)[source]#

Bases: object

Defines conditional styling rules for DataTable cells or rows.

This class allows you to apply CSS classes to table cells or rows based on the content of a specific cell. It’s used for conditional formatting, like highlighting negative values in red or flagging certain status values.

Example

from wildewidgets import BaseDataTable, DataTableStyler, DataTableColumn

# Style the status column with "text-danger" when value is "error"
styler = DataTableStyler(
    is_row=False,
    test_cell="status",
    cell_value="error",
    css_class="text-danger"
)

# Style the entire row with "table-warning" when status is "pending"
row_styler = DataTableStyler(
    is_row=True,
    test_cell="status",
    cell_value="pending",
    css_class="table-warning"
)

table = BaseDataTable(
    title="My Data Table",
    columns=[
        DataTableColumn(field="name", verbose_name="Name"),
        DataTableColumn(field="status", verbose_name="Status"),
    ],
)

table.add_styler(styler)
table.add_styler(row_styler)
Parameters:
  • is_row – Whether to apply styling to the entire row (True) or just a cell (False)

  • test_cell – The name of the column to test for the condition

  • cell_value – The value to compare against for the condition

  • css_class – The CSS class to apply when the condition is met

Keyword Arguments:

target_cell – The name of the column to style (if None, uses test_cell)

Base#

class BaseDataTable(*args, width: str | None = None, height: str | None = None, title: str | None = None, searchable: bool | None = True, paging: bool | None = True, page_length: int | None = None, small: bool | None = None, buttons: bool | None = None, striped: bool | None = None, hide_controls: bool | None = None, table_id: str | None = None, sort_ascending: bool | None = None, data: list[Any] | None = None, form_actions: Any = None, form_url: str | None = None, ajax_url_name: str | None = None, column_wrap_fields: list[str] | None = None, is_async: bool | None = None, has_select_all: bool | None = None, **kwargs)[source]#

Bases: Widget, WidgetInitKwargsMixin, DatatableAJAXView

Base class for creating interactive dataTables with sorting, filtering, and pagination.

This class provides the foundation for building powerful data tables with features like:

  • Client-side or server-side processing

  • Column sorting and filtering

  • Pagination

  • Custom styling and formatting

  • Action buttons for row operations

  • Bulk actions through form submissions

The BaseDataTable can operate in two modes:

  1. Synchronous mode: All data is loaded and processed in the browser

  2. Asynchronous mode: Data is loaded via AJAX from the server as needed

Example

from wildewidgets import BaseDataTable

class UserTable(BaseDataTable):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.add_column("username", "Username")
        self.add_column("email", "Email")
        self.add_column("date_joined", "Joined")

    def render_date_joined_column(self, row, column):
        return row.date_joined.strftime("%Y-%m-%d")
Parameters:

*args – Positional arguments passed to the parent Widget class

Keyword Arguments:
  • title – The title of the table, displayed above the table controls

  • width – CSS width for the table (default is “100%”)

  • height – CSS height for the table (optional)

  • searchable – Whether to show a search input (default is True)

  • paging – Whether to enable pagination (default is True)

  • page_length – Number of rows per page (default is 25)

  • small – Use smaller font and row height (default is False)

  • buttons – Add export buttons (default is False)

  • striped – Use alternating row colors (default is False)

  • hide_controls – Hide pagination and search controls (default is False)

  • table_id – Custom CSS ID for the table (random if None)

  • sort_ascending – Default sort order for the table (default is True)

  • data – Initial data to populate the table (optional, empty by default)

  • form_actions – List of bulk actions for selected rows (optional)

  • form_url – URL to submit form actions (optional)

  • ajax_url_name – URL name for the AJAX endpoint (default is “wildewidgets_json”)

  • column_wrap_fields – List of fields to wrap in table controls (optional)

  • is_async – If True, use AJAX to load data when the table is empty

  • True) ((default is) –

  • has_select_all – If True and form_actions is set, show a “select all” checkbox in the checkbox column header (default is False)

  • **kwargs – Keyword arguments for parent Widget class initialization

add_column(field: str, verbose_name: str | None = None, searchable: bool = True, sortable: bool = True, align: str = 'left', head_align: str = 'left', visible: bool = True, wrap: bool = True) None[source]#

Add a column to the table definition.

This method defines a new column in the table. The table will look for a method named render_{field}_column to handle custom rendering of the column’s cell values.

Parameters:
  • field – The name of the field/attribute to render in this column

  • verbose_name – Display name for the column header (defaults to capitalized field name)

  • searchable – Whether this column is included in global search

  • sortable – Whether the table can be sorted by this column

  • align – Horizontal alignment for cell content (“left”, “right”, “center”)

  • head_align – Horizontal alignment for the header cell (“left”, “right”, “center”)

  • visible – Whether the column is initially visible

  • wrap – Whether to wrap content in this column

Example

from wildewidgets import BaseDataTable

table = BaseDataTable(
    title="User List",
    searchable=True,
    paging=True,
    page_length=10
)

table.add_column(
    "created_at",
    "Created",
    align="right",
    sortable=True
)
add_filter(field: str, dt_filter: DataTableFilter) None[source]#

Add a filter control for a specific column.

Filters allow users to narrow down data based on column values.

Parameters:
  • field – The name of the field/column to filter

  • dt_filter – A DataTableFilter instance defining the filter behavior

Example

from wildewidgets import BaseDataTable, DataTableFilter

table = BaseDataTable(
    title="User List",
    searchable=True,
    paging=True,
    page_length=10
)

table.add_filter(
    "status",
    DataTableFilter(
        choices=[("active", "Active"), ("inactive", "Inactive")]
    )
)
add_form_action(action: Any) None[source]#

Add a new form action to this table.

Form actions appear in a dropdown when rows are selected via checkboxes.

Parameters:

action – The form action to add (usually a tuple of label and handler)

add_row(**kwargs) None[source]#

Add a row to the table’s data.

This method is used for synchronous tables to add data directly.

Parameters:

**kwargs – Field values as key-value pairs, where keys match column names

Example

from wildewidgets import BaseDataTable

table = BaseDataTable(
    title="User List",
    searchable=True,
    paging=True,
    page_length=10
)

table.add_row(
    username="johndoe",
    email="john@example.com",
    date_joined="2023-01-15"
)
add_styler(styler: DataTableStyler) None[source]#

Add a style rule to the table.

Stylers allow conditional formatting of cells based on their values or the values of other cells in the same row.

Parameters:

styler – A wildewidgets.DataTableStyler instance defining the styling rule

Example

from wildewidgets import BaseDataTable, DataTableStyler

table = BaseDataTable(
    title="User List",
    searchable=True,
    paging=True,
    page_length=10
)

# Style the "status" column red when its value is "error"
table.add_styler(
    DataTableStyler(
        test_cell="status",
        test_value="error",
        css_class="text-danger"
    )
)
build_context(**kwargs) dict[str, Any][source]#

Build the context for synchronous table rendering.

This method adds the table’s row data to the context for template rendering. Override this method to customize how data is prepared for the template.

Parameters:

**kwargs – The template context to update

Returns:

The updated context with row data

Return type:

dict

get_column_number(name: str) int[source]#

Get the numerical index of a column in the table by its name.

This is useful when you need to reference columns in JavaScript operations or when configuring DataTables-specific functionality.

Parameters:

name – The field name of the column to find

Returns:

Zero-based index of the column in the table

Return type:

int

Raises:

IndexError – If no column with the given name exists in the table

get_content(**kwargs) str[source]#

Render the table to HTML.

This method generates the complete HTML for the table by rendering the template with the prepared context.

Parameters:

**kwargs – Additional context values to include

Returns:

The rendered HTML for the table

Return type:

str

get_form_actions() Any[source]#

Get the list of form actions defined for this table.

Returns:

The form_actions list or None if no actions are

defined

Return type:

Any

get_template_context_data(**kwargs) dict[str, Any][source]#

Prepare the complete context for table template rendering.

This method builds the context dictionary with all necessary data for rendering the table template, including configuration, filters, headers, and data mode (async or sync).

Parameters:

**kwargs – Initial context values

Returns:

Complete context dictionary for template rendering

Return type:

dict

has_form_actions() bool[source]#

Check if this table has form actions defined.

Form actions allow users to perform bulk operations on selected rows by checking the checkboxes and submitting the form.

Returns:

True if form actions are defined, False otherwise

Return type:

bool

remove_filter(field: str) None[source]#

Remove a previously defined filter from a column.

Parameters:

field – The name of the field/column to remove the filter from

render_checkbox_column(row: Any, column: str) str[source]#

Render the checkbox column for form actions.

This method generates the HTML for the checkbox in each row when form_actions are enabled. The checkbox uses the row’s ID as its value.

Parameters:
  • row – The data object for the current row

  • column – The column name (always “checkbox”)

Returns:

HTML for the checkbox input

Return type:

str

ajax_url_name: str = 'wildewidgets_json'#

The URL name for the dataTables AJAX endpoint

buttons: bool = False#

If True, add the dataTable “Copy”, “CSV”, “Export” and “Print” buttons

column_fields: dict[str, DataTableColumn]#

A mapping of field name to column definition

column_filters: dict[str, DataTableFilter]#

A mapping of field name to column filter definition

column_styles: list[DataTableStyler]#

A list of column styles to apply

column_wrap_fields: list[str] = []#

The header fields to wrap in the table controls

datatable_options: dict[str, Any]#

These are options for dataTable itself and get set in the JavaScript constructor for the table.

form_actions = None#

Whole table form actions. If this is not None, add a first column with checkboxes to each row, and a form that allows you to choose bulk actions to perform on all checked rows.

form_url: str = ''#

The URL to which to POST our form actions if form_actions is not None

has_select_all: bool = False#

If True and form_actions is set, show a “select all” checkbox in the checkbox column header. Default is False so existing tables are unchanged.

height: str | None = None#

How tall should we make the table? Any CSS width string is valid.

hide_controls: bool = False#

Hide our paging, page length and search controls

is_async: bool = True#

If True, use AJAX to load data when the table is empty

page_length: int = 25#

How many rows should we show on each page

searchable: bool = True#

Show the search input?

small: bool = False#

If True, use smaller font and row height when rendering rows

sort_ascending: bool = True#

If True, sort rows ascending; otherwise descending.

striped: bool = False#

If True, use different colors for even and odd rows

table_id: str | None = None#

The CSS id for this table

template_file: str = 'wildewidgets/table.html'#

The Django template file to use for rendering the table

width: str | None = '100%'#

How wide should we make the table? Any CSS width string is valid.

Views#

class BaseDatatableView(model: type[models.Model] | None = None, order_columns: list[str] | None = None, max_display_length: int | None = None, none_string: str | None = None, is_data_list: bool | None = None, escape_values: bool | None = None, **kwargs)[source]#

Bases: DatatableMixin, JSONResponseView

Base view for handling dataTables.js server-side processing.

This class combines the dataTables.js processing functionality from DatatableMixin with the JSON response handling from wildewidgets.JSONResponseView to create a complete server-side processing view for dataTables.js.

Extend this class and override the necessary methods to create a custom dataTables.js server-side processing view.

class DatatableAJAXView(model: type[models.Model] | None = None, order_columns: list[str] | None = None, max_display_length: int | None = None, none_string: str | None = None, is_data_list: bool | None = None, escape_values: bool | None = None, **kwargs)[source]#

Bases: BaseDatatableView

Enhanced view for handling dataTables.js AJAX requests with advanced features.

This class extends BaseDatatableView with additional functionality for:

  • Advanced column configuration parsing

  • Per-column filtering and searching

  • Support for dotted attribute notation and relationship traversal

  • Custom column rendering based on method naming conventions

It’s designed to be extended for specific datatables, with custom filtering and rendering logic implemented through method overrides.

Example

class UserTableView(DatatableAJAXView):
    model = User
    columns = ['id', 'username', 'email', 'is_staff', 'date_joined']

    def render_is_staff_column(self, row, column):
        return '✓' if row.is_staff else '✗'

    def render_date_joined_column(self, row, column):
        return row.date_joined.strftime('%Y-%m-%d')
column_specific_searches() list[tuple[str, str]][source]#

Get a list of active per-column search filters.

This method identifies columns that have search values specified in the DataTables request, which happens when a user enters a search term in a specific column’s filter input.

Returns:

List of (column_name, search_value) pairs

Return type:

list[tuple[str, str]]

columns(querydict: dict[str, Any]) dict[str, Any][source]#

Parse dataTables.js column configuration into a more usable format.

This method converts the flattened column configuration from dataTables.js into a nested dictionary structure that’s easier to work with. It maps column data by column name rather than index for more intuitive access.

Note

This overrides the columns attribute from DatatableMixin to provide a more advanced parsing mechanism.

Parameters:

querydict – The query parameters from the dataTables.js request

Returns:

Dictionary mapping column names to their configuration

Return type:

dict[str, Any]

filter_queryset(qs: models.QuerySet) models.QuerySet[source]#

Apply all filtering to the queryset based on dataTables.js parameters.

This method handles both:

  1. Per-column searches specified by column-specific filters

  2. Global searches from the main dataTables.js search input

Parameters:

qs – The queryset to filter

Returns:

The filtered queryset

Return type:

models.QuerySet

render_column(row: Any, column: str) str[source]#

Render a column value with custom rendering support.

This method enables custom column rendering through convention-based method naming. If a method named render_COLUMNNAME_column exists, it will be called to render the column instead of the default implementation.

Parameters:
  • row – The model instance or dictionary for this row

  • column – The column name

Returns:

The rendered column value

Return type:

str

Example

To customize rendering for a ‘status’ column:

def render_status_column(self, row: Model, column: str) -> str:
    status = row.status
    if status == 'active':
        return f'<span class="badge bg-success">{status}</span>'
    return f'<span class="badge bg-secondary">{status}</span>'
search(qs: models.QuerySet, value: str) models.QuerySet[source]#

Apply a global search across all searchable columns.

This method is called when a user enters a search term in the main dataTables.js search input. It applies the search across all searchable columns and returns distinct results.

Parameters:
  • qs – The queryset to search

  • value – The search term

Returns:

The filtered queryset containing only matching records

Return type:

models.QuerySet

search_query(qs: models.QuerySet, value: str) Q | None[source]#

Build a Q object for performing global search across multiple columns.

This method constructs a query that searches all searchable columns for the given value, using OR logic to match records that have the value in any searchable column.

Parameters:
  • qs – The queryset (not used in the default implementation)

  • value – The search term to look for

Returns:

A Django Q object representing the search, or None if no

searchable columns exist

Return type:

Q | None

searchable_columns() list[str][source]#

Get the list of column names that are marked as searchable.

This method parses the column configuration to identify which columns should be included in global searches and per-column filtering. The result is cached for performance.

Returns:

List of searchable column names

Return type:

list[str]

single_column_filter(qs: models.QuerySet, column: str, value: str) models.QuerySet[source]#

Apply filtering to a queryset based on a single column search.

This method filters the queryset by a specific column value. It supports:

  1. Custom filtering via filter_COLUMNNAME_column methods

  2. Default icontains filtering for searchable columns

Parameters:
  • qs – The queryset to filter

  • column – The column name to filter on

  • value – The search value to filter by

Returns:

The filtered queryset

Return type:

models.QuerySet

Example

To implement custom filtering for a specific column:

from django.db.models import QuerySet

def filter_status_column(
    self,
    qs: QuerySet,
    column: str,
    value: str
) -> QuerySet:
    if value.lower() == 'active':
        return qs.filter(is_active=True)
    elif value.lower() == 'inactive':
        return qs.filter(is_active=False)
    return qs
class DatatableMixin(model: type[models.Model] | None = None, order_columns: list[str] | None = None, max_display_length: int | None = None, none_string: str | None = None, is_data_list: bool | None = None, escape_values: bool | None = None, **kwargs)[source]#

Bases: object

A mixin that provides server-side processing for jQuery DataTables.

This mixin handles all the server-side processing required by jQuery DataTables, including sorting, filtering, searching, and pagination. It can work with Django QuerySets and provides a customizable framework for rendering data.

The mixin works with both older (<1.10) and newer versions of DataTables, automatically adapting to the format of parameters sent by the client.

Example

class MyDatatableView(DatatableMixin, JSONResponseView):
    model = MyModel
    columns = ['id', 'name', 'description']
    order_columns = ['id', 'name', 'description']

    def render_description_column(self, row, column):
        return f"{row.description[:50]}..."
extract_datatables_column_data() list[dict[str, str]][source]#

Extract column configuration data from the dataTables.js request.

This method parses the complex column configuration parameters sent by dataTables.js 1.10+ into a more manageable structure for internal use.

Returns:

List of column configuration dictionaries

Return type:

list[dict[str, str]]

get_columns() list[str][source]#

Get the list of columns to display in the datatable.

This method determines which columns will be included in the response. It first checks the columns attribute, then falls back to extracting column information from the dataTables.js request parameters if using newer versions.

Returns:

List of column names to display

Return type:

list[str]

get_context_data(*args, **kwargs)[source]#

Process the DataTables request and prepare the response data.

This is the main entry point that:

  1. Initializes the configuration based on the request

  2. Gets the initial queryset

  3. Applies filtering, sorting, and pagination

  4. Formats the results as expected by DataTables

Parameters:

*args – Variable length argument list

Keyword Arguments:

**kwargs – Arbitrary keyword arguments

Returns:

Response data in the format expected by DataTables

Return type:

dict

Note

The returned dictionary contains different keys depending on the dataTables.js version in use.

get_filter_method() str[source]#

Get the preferred Django queryset filter method for searches.

This determines how text searching is performed on columns. By default, uses “istartswith” for case-insensitive prefix matching, but can be overridden to use other methods like “icontains” for substring matching.

Returns:

The filter method string (e.g., “istartswith”, “icontains”)

Return type:

str

get_initial_queryset() models.QuerySet[source]#

Get the initial queryset for the datatable.

By default, returns all objects from the model specified in the model attribute. Override this method to provide custom querysets, filtering by user permissions, or any other logic needed to determine the base dataset.

Returns:

The initial queryset for the datatable

Return type:

QuerySet

Raises:

NotImplementedError – If no model is specified and this method is not overridden

get_order_columns() list[str][source]#

Get the list of columns that can be used for ordering/sorting.

This method returns the columns that can be sorted in the datatable. It first checks the order_columns attribute, then falls back to extracting column information from the dataTables.js request parameters if using newer versions.

Returns:

List of column names that can be sorted

Return type:

list[str]

handle_exception(e: Exception) NoReturn[source]#

Handle exceptions that occur during processing.

This method logs the exception and re-raises it by default. Override this method to implement custom exception handling.

Parameters:

e – The exception that was raised

Raises:

Exception – Re-raises the original exception

initialize(*args, **kwargs)[source]#

Initialize the datatable by determining the DataTables version in use.

This method checks request parameters to detect whether the client is using DataTables <1.10 (which uses different parameter naming conventions), and configures the mixin accordingly.

Parameters:
  • *args – Variable length argument list

  • **kwargs – Arbitrary keyword arguments

ordering(qs: models.QuerySet) models.QuerySet[Model][source]#

Apply ordering to the queryset based on dataTables.js parameters.

This method parses sorting parameters from the dataTables.js request and applies them to the queryset. It supports multi-column sorting and handles both older and newer dataTables.js parameter formats.

Parameters:

qs – The queryset to order

Returns:

The ordered queryset

Return type:

models.QuerySet

paging(qs: models.QuerySet) models.QuerySet[source]#

Apply pagination to the queryset based on dataTables.js parameters.

This method extracts pagination parameters (start position and length) from the dataTables.js request and slices the queryset accordingly.

Parameters:

qs – The queryset to paginate

Returns:

The paginated queryset

Return type:

models.QuerySet

prepare_results(qs: models.QuerySet) list[list[str]] | list[dict[str, Any]][source]#

Transform queryset results into the format expected by dataTables.js.

This method converts Django model instances into either:

It calls render_column for each value to allow custom formatting.

Parameters:

qs – The queryset containing the results to display

Returns:

Either a list of lists (row-based format) or a list of dictionaries (column-based format) depending on the DataTables configuration

render_column(row: Any, column: str) str[source]#

Render a column value for display in the datatable.

This is the main method for formatting column values. Override this or create methods named get_FIELDNAME_display on your Django model to customize how specific columns are displayed. See _render_column for details on how to implement custom rendering logic.

Parameters:
  • rowModel instance or dictionary for the current row

  • column – Column name

Returns:

The rendered value as a string, ready for display

Return type:

str

FILTER_ICONTAINS: Final[str] = 'icontains'#

The filter method to use for global searches and single column filtering for case-insensitive “contins” searches

FILTER_ISTARTSWITH: Final[str] = 'istartswith'#

The filter method to use for global searches and single column filtering for case-insensitive “startswith” searches

columns: list[str] = []#

The names of the columns to display in our table

columns_data: list[dict[str, Any]] = []#

This gets set by the dataTables Javascript when it does the AJAX call

escape_values: bool = True#

If set to True then values returned by render_column` will be escaped

is_data_list: bool = True#

This determines the type of results. If the AJAX call passes us a data attribute that is not an integer, it expects a dictionary with specific fields in the response, see: dataTables columns.data

max_display_length: int = 100#

The max number of of records that will be returned, so that we can protect our our server from rendering huge amounts of data

model: type[models.Model] | None = None#

The Django model that this datatable will be based on. If not provided, you must implement the get_initial_queryset method to return a queryset.

none_string: str = ''#

Replace any column value that is None with this string

order_columns: list[str] = []#

The list of column names by which the table will be ordered.

pre_camel_case_notation: bool = False#

Set to True if you are using datatables < 1.10

Actions#

class ActionButtonBlockMixin(*args, actions: list[wildewidgets.widgets.tables.actions.RowActionButton] | None = None, button_size: str | None = None, justify: Optional[Literal['start', 'center', 'end']] = None, **kwargs)[source]#

Bases: object

A mixin for wildwidgets.DataTable classes that adds action buttons using RowActionButton classes.

This mixin provides a more object-oriented approach to adding action buttons compared to ActionsButtonsBySpecMixin. It uses RowActionButton instances for greater flexibility and extensibility.

Important

Typically, you will not use this directly, but rather use wildewidgets.StandardActionButtonModelTable or wildewidgets.LookupModelTable, which already has this built in as a mixin.

Example

from wildewidgets import ActionButtonBlockMixin, DataTable

class MyTable(ActionButtonBlockMixin, DataTable):
    actions = [
        RowEditButton(),
        RowDeleteButton()
    ]
    ...
Parameters:

*args – Positional arguments for the parent class

Keyword Arguments:
  • actions – List of RowActionButton instances to add to the “Actions” column. If not provided, a default “View” button is used.

  • button_size – Size of the action buttons (default: None)

  • justify – Justification of the action buttons in the “Actions” column (default: “end”)

get_actions() list[wildewidgets.widgets.tables.actions.RowActionButton][source]#

Get the list of action buttons to display.

Override this in subclasses to dynamically determine which buttons to show.

Returns:

List of action button instances

Return type:

list[RowActionButton]

get_content(**kwargs) str[source]#

Get the rendered content for the table, including action columns.

Parameters:

**kwargs – Keyword arguments for content generation

Returns:

The HTML content for the table

Return type:

str

render_actions_column(row: Any, column: str) str[source]#

Render all action buttons for a specific row.

Creates a horizontal layout containing all visible action buttons for the given row.

Parameters:
  • row – The row data to render buttons for

  • column – The column name (ignored, always “actions”)

Returns:

Complete HTML for the actions column

Return type:

str

Note

Buttons are only shown if their is_visible method returns True for the current user.

actions: list[wildewidgets.widgets.tables.actions.RowActionButton] = [<wildewidgets.widgets.tables.actions.RowModelUrlButton object>]#

A list of RowActionButton subclasses to display in the “Actions” column.

button_size: str | None = None#

If not None, make all per-row action buttons be this size.

justify: Literal['start', 'center', 'end'] = 'end'#

The justification of the action buttons in the “Actions” column.

class ActionsButtonsBySpecMixin(*args, actions: Any = None, action_button_size: str | None = None, default_action_button_label: str | None = None, default_action_button_color_class: str | None = None, **kwargs)[source]#

Bases: object

A mixin for wildewidgets.DataTable classes and subclasses that adds action buttons based on specifications.

This mixin allows you to add action buttons to the rightmost column of a table by specifying them as tuples that define their behavior. It provides a simple way to create standard actions without needing to define button classes.

Actions are specified as tuples with these elements, in this order:

  1. Label (str): The button text

  2. URL name (str): Django URL pattern name, e.g., “app:item-view”. We’ll reverse this to get the URL.

  3. Method (str, optional): “get” or “post” (default: “get”)

  4. Color (str, optional): Bootstrap color class (default: “secondary”)

  5. Field name (str, optional): ID field name (default: “id”)

  6. JS function (str, optional): JavaScript function to call

Example

from wildewidgets import ActionsButtonsBySpecMixin

class MyDataTable(ActionsButtonsBySpecMixin, DataTable):
    actions = [
        ("View", "app:item-view"),
        ("Edit", "app:item-edit", "get", "primary"),
        ("Delete", "app:item-delete", "post", "danger", "id",
        "confirmDelete")
    ]

This will add an “Actions” column with buttons for each specified action. Each button will be rendered with the appropriate URL and method based on the row data.

Parameters:

*args – Positional arguments for the parent class

Keyword Arguments:
  • actions – List of action specifications to add to the table

  • action_button_size – Size of the action buttons (default: “normal”)

  • default_action_button_label – Default label for the action button (default: “View”)

  • default_action_button_color_class – Default color class for the action button (default: “secondary”)

  • **kwargs – Keyword arguments for the parent class

get_action_button(row: Any, label: str, url_name: str, method: str = 'get', color_class: str = 'secondary', attr: str = 'id', js_function_name: str | None = None) str[source]#

Create an action button for a specific row using a Django URL name.

Parameters:
  • row – The row data this button is for

  • label – Text to display on the button

  • url_name – Django URL pattern name to link to

  • method – HTTP method to use (“get” or “post”)

  • color_class – Bootstrap color class

  • attr – Row attribute to use as ID parameter

  • js_function_name – Optional JavaScript function to call on click

Returns:

HTML for the rendered button

Return type:

str

get_action_button_url_extra_attributes(row: Any) str[source]#

Get additional URL query parameters for action buttons.

Override this in subclasses to add custom query parameters.

Parameters:

row – The row data this button is for

Returns:

Additional URL query parameters

Return type:

str

get_action_button_with_url(row: Any, label: str, url: str, method: str = 'get', color_class: str = 'secondary', attr: str = 'id', js_function_name: str | None = None) str[source]#

Create an action button for a row with a specific URL.

Parameters:
  • row – The row data this button is for

  • label – Text to display on the button

  • url – Complete URL to link to

  • method – HTTP method to use (“get” or “post”)

  • color_class – Bootstrap color class

  • attr – Row attribute to use as ID parameter for POST forms

  • js_function_name – Optional JavaScript function to call on click

Returns:

HTML for the rendered button

Return type:

str

get_conditional_action_buttons(row: Any) str[source]#

Get additional action buttons based on row data.

Override this in subclasses to add buttons conditionally based on row attributes.

Parameters:

row – The row data to evaluate

Returns:

HTML for additional buttons

Return type:

str

get_content(**kwargs) str[source]#

Get the rendered content for the table, including action columns.

Parameters:

**kwargs – Keyword arguments for content generation

Returns:

The HTML content for the table

Return type:

str

get_template_context_data(**kwargs) dict[str, Any][source]#

Add action column information to the template context.

Parameters:

**kwargs – Keyword arguments to update

Returns:

Updated context dictionary with action column information

Return type:

dict

render_actions_column(row: Any, column: str) str[source]#

Render all action buttons for a specific row.

This method generates the complete HTML for the actions column, including: 1. The default view button if the model has get_absolute_url 2. All buttons defined in the actions specification 3. Any conditional buttons from get_conditional_action_buttons

Parameters:
  • row – The row data to render buttons for

  • column – The column name (ignored, always “actions”)

Returns:

Complete HTML for the actions column

Return type:

str

action_button_size: str = 'normal'#

How big should each action button be? One of normal, btn-lg, or btn-sm.

actions: Any = False#

Per row action buttons. If not False, this will simply add a rightmost column named Actions with a button named default_action_button_label which when clicked will take the user to the

default_action_button_color_class: str = 'secondary'#

The Bootstrap color class to use for the default action buttons

default_action_button_label: str = 'View'#

The label to use for the default action button

class RowActionButton(text: str | None = None, url: str | Callable[[Any], str] | None = None, color: str | None = None, size: str | None = None, permission: str | None = None, **kwargs)[source]#

Bases: Block

Base class for action buttons displayed in table rows.

This class provides the foundation for creating buttons that appear in the “Actions” column of tables. Each button is bound to a specific row and can perform actions based on that row’s data. Note that all keyword arguments/class attributes from wildewidgets.Block are also accepted.

You can use this class directly with keyword arguments to create buttons that link to row-specific URLs. In order for this to work, you’ll need to pass a callable into url that accepts a single argument, which will be the row data. This callable should return a string that is the URL for the button.

You will more usually subclass this, setting class attributes to create specific model-based buttons, and overriding the get_url method to return the URL for the button based on the row data.

tag#

HTML tag for the button, defaults to “a” for links

Type:

str

text#

The text displayed on the button

Type:

str | None

url#

The URL the button links to, a Django URL name to reverse, or a callable that accepts a row arg and returns a URL string

Type:

str | Callable[[Any], str] | None

color#

Bootstrap color class for the button (e.g., “primary”, “secondary”)

Type:

str

size#

Bootstrap size class for the button (e.g., “sm”, “lg”)

Type:

str | None

permission#

Optional Django permission string required to see the button

Type:

str | None

row#

Reference to the row data this button is bound to (set by bind method)

Example

Direct usage with keyword arguments:

from django.urls import reverse
from wildewidgets import RowActionButton

def get_home_url(row: Any) -> str:
    return reverse("app:home", kwargs={"id": row.id})

button = RowActionButton(
    text="Home",
    url=get_home_url,
    color="primary",
    permission="app.view_item"
)

Subclassing for specific actions:

class RowViewButton(RowActionButton):
    text = "View"
    color = "info"
    size = "sm"
    url = "core:item-view"

    def get_url(self, row: Any) -> str:
        return reverse(self.url, kwargs={"id": row.id})
Keyword Arguments:
  • text – The text to display on the button

  • url – The URL the button should link to

  • color – The Bootstrap color class for the button (default: “secondary”)

  • size – The Bootstrap size class for the button (default: None)

  • permission – Optional Django permission string required to see this button, e.g. “app.view_item”

  • **kwargs – Additional attributes passed to the parent Block class

Raises:

ImproperlyConfigured – If ‘text’ or ‘url’ is not provided

bind(row: Any, table: ActionButtonBlockMixin, size: str | None = None) RowActionButton[source]#

Bind this button to a specific row and return a copy configured for that row.

This method creates a copy of the button configured specifically for the given row, including setting appropriate URLs, colors and sizes.

Parameters:
  • row – The row data to bind this button to

  • table – The table instance that contains this row

  • size – Optional size override for the button

Returns:

A new button instance bound to the specified row

Return type:

RowActionButton

Note

The table parameter provides access to table-level properties like CSRF tokens needed for form submissions.

get_url(row: Any) str[source]#

Get the URL for this button, potentially based on row data.

This base implementation simply returns the static URL property. Subclasses can override this to generate dynamic URLs based on row data.

Parameters:

row – The row data to use for URL generation

Returns:

The URL for the button

Return type:

str

is_visible(row: Any, user: AbstractUser | None) bool[source]#

Determine if this button should be visible to the given user.

Parameters:
  • row – The row data this button is associated with

  • user – The current Django user

Returns:

True if the button should be visible, False otherwise

Return type:

bool

Note

If a permission is specified, the user must have that permission for the button to be visible.

row: Any#

The table will set this

tag: str = 'a'#

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

class RowDeleteButton(form_fields: list[str] | None = None, confirm_text: str | None = None, **kwargs)[source]#

Bases: RowFormButton

A pre-configured button for deleting a row’s model instance.

This is a convenience subclass of RowFormButton configured specifically for delete operations. It submits the row’s ID via POST to the URL returned by the model’s get_delete_url method by default.

Either subclass this, setting class attributes to create specific model-based buttons, or use it directly with keyword arguments to create buttons that link to model-specific URLs. Note that all keyword arguments/class attributes from wildewidgets.Block and RowModelUrlButton are also accepted.

Important

Your model must implement a method or attribute named attribute, which must return the URL to submit the form to for deletion. By default, this is get_delete_url.

The form submitted will have by default the following fields:

  • csrf_token: CSRF token for security

  • id: The ID of the row’s model instance

Thus, your delete view should expect a POST request with these fields.

Note

The confirmation text is generated using the row’s string representation, so ensure your model has a meaningful __str__ method. If you need a custom confirmation message, subclass and override get_confirm_text.

attribute#

The model method or attribute to call/access for the URL (“get_delete_url”)

Type:

str

text#

Default button text (“Delete”)

Type:

str

color#

Default Bootstrap color (“outline-secondary”)

Type:

str

form_fields#

Default field to submit ([“id”])

Type:

list[str]

Example

Direct usage with keyword arguments:

from wildewidgets import RowDeleteButton

# Simple usage - requires model.get_delete_url() to exist
button = RowDeleteButton()

Subclassing for specific actions:

class RowCustomDeleteButton(RowDeleteButton):

attribute = “get_custom_delete_url” text = “Remove” color = “danger” form_fields = [“id”, “name”] # Submit additional fields

get_confirm_text(row: Any) str[source]#

Generate a confirmation message for deleting this row.

Creates a message like ‘Delete “Item Name”?’ using the row’s string representation.

Parameters:

row – The row data to create a confirmation message for

Returns:

The confirmation message to display

Return type:

str

class RowDjangoUrlButton(url_path: str | None = None, url_args: list[str] | None = None, url_kwargs: dict[str, str] | None = None, **kwargs)[source]#

Bases: RowActionButton

A row action button that constructs its URL using Django’s URL resolver.

This button uses Django’s URL resolution system with either positional or keyword arguments to construct its URL dynamically based on row data.

Either subclass this, setting class attributes to create specific model-based buttons, or use it directly with keyword arguments to create buttons that link to model-specific URLs. Note that all keyword arguments/class attributes from wildewidgets.Block and RowActionButton are also accepted.

block#

CSS class for styling (“btn”)

Type:

str

url_path#

The Django URL pattern name to reverse, e.g., “app:item-edit”

Type:

str | None

url_args#

List of row attribute names to use as positional arguments

Type:

list[str]

url_kwargs#

Dictionary mapping URL param names to row attribute names

Type:

dict[str, str]

Example

Direct usage with keyword arguments:

from wildewidgets import RowDjangoUrlButton

# Using positional arguments (e.g., 'item/1/')
button = RowDjangoUrlButton(
    text="Edit",
    url_path="app:item-edit",
    url_args=["id"]
)

# Using keyword arguments (e.g., 'item/edit/?pk=1')
button = RowDjangoUrlButton(
    text="Edit",
    url_path="app:item-edit",
    url_kwargs={"pk": "id"}
)

Subclassing for specific actions:

class RowEditButton(RowDjangoUrlButton):
    url_path = "app:item-edit"
    text = "Edit"
    color = "primary"
    url_args = ["id"]

Note

You must specify either url_args or url_kwargs, but not both.

Keyword Arguments:
  • url_path – The Django URL pattern name to reverse

  • url_args – List of row attribute names to use as positional arguments

  • url_kwargs – Dictionary mapping URL param names to row attribute names

Raises:
  • ImproperlyConfigured – If both url_args and url_kwargs are provided, or if url_path is not set

  • RowActionButton.RequiredAttrOrKwarg – If url_path is not set

get_url(row: Any) str[source]#

Construct a URL using Django’s URL resolver with row data.

Parameters:

row – The row data to use for URL parameters

Returns:

The resolved URL for the button

Return type:

str

block: str = 'btn'#

block is the official wildewidgets name of the block; it can’t be changed by constructor kwargs

class RowEditButton(attribute: str | None = None, **kwargs)[source]#

Bases: RowModelUrlButton

A pre-configured button for editing a row’s model instance.

This is a convenience subclass of RowModelUrlButton configured specifically for edit operations. It looks for a get_update_url method on the model.

Either subclass this, setting class attributes to create specific model-based buttons, or use it directly with keyword arguments to create buttons that link to model-specific URLs. Note that all keyword arguments/class attributes from wildewidgets.Block and RowModelUrlButton are also accepted.

attribute#

The model method to call for URL (“get_update_url”). Your model must implement this method or attribute to return the URL for editing.

Type:

str

text#

Default button text (“Edit”)

Type:

str

color#

Default Bootstrap color (“primary”)

Type:

str

Example

Direct usage with keyword arguments:

from wildewidgets import RowEditButton

# Simple usage - requires model.get_update_url() to exist
button = RowEditButton()

# Custom text
button = RowEditButton(text="Modify")

Subclassing for specific actions:

class RowCustomEditButton(RowEditButton):

attribute = “get_custom_update_url” text = “Modify” color = “warning” url_args = [“id”]

class RowFormButton(form_fields: list[str] | None = None, confirm_text: str | None = None, **kwargs)[source]#

Bases: RowModelUrlButton

A row action button that renders as a form, submitting via POST.

This button renders as an HTML form that submits via POST when clicked. It’s ideal for actions that modify data, like delete or status change operations. You do not need to provide a form – it will be created automatically.

Either subclass this, setting class attributes to create specific model-based buttons, or use it directly with keyword arguments to create buttons that link to model-specific URLs. Note that all keyword arguments/class attributes from wildewidgets.Block and RowModelUrlButton are also accepted.

block#

CSS class for styling (“action-form”)

Type:

str

tag#

HTML tag for the container (“form”)

Type:

str

form_fields#

List of row attribute names to include as hidden fields

Type:

list[str]

confirm_text#

Confirmation message to show before submission

Type:

str | None

Example

Direct usage with keyword arguments:

from wildewidgets import RowFormButton

button = RowFormButton(
    text="Delete",
    attribute="get_delete_url",
    form_fields=["id"],
    confirm_text="Are you sure you want to delete this item?"
)

Subclassing for specific actions:

class RowDeleteButton(RowFormButton):
    attribute = "get_delete_url"
    text = "Delete"
    color = "outline-secondary"
    form_fields = ["id"]
    confirm_text = "Are you sure you want to delete this item?"

Note

  • Requires both form_fields and confirm_text to be specified

  • Will include CSRF token automatically

  • The form action URL is determined by the attribute method or attribute, which must be present on the model class. If you need more sophisticated URL handling, subclass and override the get_url method.

Keyword Arguments:
  • form_fields – List of row attribute names to include as hidden fields

  • confirm_text – Confirmation message to show before submission

Raises:

ImproperlyConfigured – If form_fields or confirm_text are not set

bind(row: Any, table: Any, size: str | None = None) RowFormButton[source]#

Bind this button to a specific row and create a form.

Creates a complete form with:

  • CSRF token

  • Hidden fields with row data

  • Submit button with confirmation dialog

Parameters:
  • row – The row data to bind this button to

  • table – The table instance that contains this row

  • size – Optional size override for the button

Returns:

A configured form button for the specified row

Return type:

RowFormButton

get_confirm_text(row: Any) str[source]#

Get the confirmation text for this button.

Parameters:

row – The row data this button is associated with

Returns:

The confirmation text to display

Return type:

str

block: str = 'action-form'#

block is the official wildewidgets name of the block; it can’t be changed by constructor kwargs

tag: str = 'form'#

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

class RowLinkButton(text: str | None = None, url: str | Callable[[Any], str] | None = None, color: str | None = None, size: str | None = None, permission: str | None = None, **kwargs)[source]#

Bases: RowActionButton

A row action button that renders as a link with appropriate attributes.

This subclass of RowActionButton ensures the rendered button has the appropriate attributes for accessibility and behavior as a link.

Either subclass this, setting class attributes to create specific model-based buttons, or use it directly with keyword arguments to create buttons that link to model-specific URLs. Note that all keyword arguments/class attributes from wildewidgets.Block and RowActionButton are also accepted.

Note

If row is going to be a Django model instance, you’re better off using RowModelUrlButton or RowDjangoUrlButton instead.

Honestly, the only difference between this and RowActionButton is that we set the role attribute on the <a> tag to “button”.

Inherits all attributes from :py:class:`RowActionButton`.

Example

Direct usage with keyword arguments:

from django.urls import reverse

from wildewidgets import RowLinkButton

def get_details_url(row: Any) -> str:
    return reverse("app:item-details", kwargs={"id": row.id})

button = RowLinkButton(
    text="Details",
    url=get_details_url,
    color="info"
)

Subclassing for specific actions:

from django.urls import reverse_lazy
from wildewidgets import RowLinkButton

class RowDetailsButton(RowLinkButton):
    text = "Details"
    color = "info"

    def get_url(self, row: Any) -> str:
        return reverse("app:item-details", kwargs={"id": row.id})
get_context_data(*args, **kwargs) dict[str, Any][source]#

Prepare the context data for template rendering.

Sets appropriate attributes for accessibility including href and role.

Parameters:
  • *args – Positional arguments passed to the parent method

  • **kwargs – Keyword arguments passed to the parent method

Returns:

The context dictionary with updated attributes

Return type:

dict

class RowModelUrlButton(attribute: str | None = None, **kwargs)[source]#

Bases: RowActionButton

A row action button that gets its URL from a model instance attribute or method.

This button uses a specified attribute or method of the row’s model instance to determine its URL, making it ideal for standard model actions like view or edit.

Either subclass this, setting class attributes to create specific model-based buttons, or use it directly with keyword arguments to create buttons that link to model-specific URLs. Note that all keyword arguments/class attributes from wildewidgets.Block and RowActionButton are also accepted.

block#

CSS class for styling (“btn”)

Type:

str

modifier#

CSS modifier class (“auto”)

Type:

str

attribute#

The model attribute or method to use for URL generation. Your model must implement this method or attribute to return the URL.

Type:

str

text#

Default button text (“View”)

Type:

str | None

Example

Direct usage with keyword arguments:

from wildewidgets import RowModelUrlButton

# Uses row.get_absolute_url() to determine URL
button = RowModelUrlButton(text="View Details")

# Uses row.get_edit_url() to determine URL
button = RowModelUrlButton(
    text="Edit",
    attribute="get_edit_url",
    color="primary"
)

Subclassing for specific actions:

class RowViewButton(RowModelUrlButton):
    attribute = "get_absolute_url"
    text = "View"
    color = "info"
    size = "sm"
Keyword Arguments:
  • attribute – The model attribute or method to use for URL generation. Your model must implement this method or attribute to return the URL.

  • **kwargs – Additional keyword arguments for the *RowActionButton class

get_url(row: Any) str[source]#

Get the URL from the specified model attribute or method.

Parameters:

row – The model instance to get the URL from

Returns:

The URL for the button

Return type:

str

Raises:

ValueError – If the specified attribute doesn’t exist on the model

block: str = 'btn'#

block is the official wildewidgets name of the block; it can’t be changed by constructor kwargs

modifier: str = 'auto'#

If specified, also add a class named {name}--{modifier} to the CSS classes

class StandardModelActionButtonBlockMixin(*args, actions: list[wildewidgets.widgets.tables.actions.RowActionButton] | None = None, button_size: str | None = None, justify: Optional[Literal['start', 'center', 'end']] = None, **kwargs)[source]#

Bases: ActionButtonBlockMixin

A ready-to-use mixin providing standard “Edit” and “Delete” buttons for model tables.

This mixin provides a convenient configuration of ActionButtonBlockMixin with “Edit” and “Delete” buttons pre-configured. It’s a quick way to add these common actions to any DataTable.

Note

This is used by wildewidgets.LookupModelTable.

Requirements:
  • Your model must implement get_absolute_url, get_update_url and get_delete_url methods

Example

from wildewidgets import StandardModelActionButtonBlockMixin, DataTable
from myapp.models import MyModel

class MyTable(StandardModelActionButtonBlockMixin, DataTable):
    model = MyModel
    fields = ["name", "description"]
    # No additional configuration needed for basic edit/delete buttons
actions: list[wildewidgets.widgets.tables.actions.RowActionButton] = [<wildewidgets.widgets.tables.actions.RowModelUrlButton object>, <wildewidgets.widgets.tables.actions.RowModelUrlButton object>]#

A list of RowActionButton subclasses to display in the “Actions” column.