Source code for wildewidgets.views.tables
from __future__ import annotations
from typing import TYPE_CHECKING, Any
from django.core.exceptions import ImproperlyConfigured
from django.http import Http404, HttpResponseRedirect
from django.views.generic import View
from django.views.generic.base import TemplateView
if TYPE_CHECKING:
from django.http import HttpRequest
from ..widgets import BaseDataTable
[docs]class TableActionFormView(View):
"""
A view that processes form actions submitted from a data table.
This view handles POST requests containing table actions (like bulk delete,
approve, etc.) and delegates the processing to action-specific methods. It
follows a convention-based approach where actions are processed by methods
named `process_{action}_action`.
To use this view:
1. Subclass it and implement methods for each action (e.g., `process_delete_action`)
2. Set the `url` attribute to specify where to redirect after processing
3. Map the view to a URL in your URLconf
Example:
.. code-block:: python
from django.http import HttpResponseRedirect
from django.urls import reverse_lazy
from django.views.generic import View
from wildewidgets import TableActionFormView
from myapp.models import User
class UserBulkActionView(TableActionFormView):
url = reverse_lazy('user-list')
def process_delete_action(self, items):
User.objects.filter(id__in=items).delete()
def process_activate_action(self, items):
User.objects.filter(id__in=items).update(is_active=True)
"""
#: The HTTP methods this view will respond to
http_method_names: list[str] = ["post"] # noqa: RUF012
#: The URL to redirect to after processing the form action
url: str | None = None
[docs] def process_form_action(self, action: str, items: list[str]) -> None:
"""
Process a form action by delegating to an action-specific method.
This method looks for a method named `process_{action}_action` and calls
it with the list of selected items. If no such method exists, the action
is silently ignored.
Args:
action: The name of the action to process (e.g., "delete", "approve")
items: List of item IDs that the action should be applied to
Example:
If `action` is "delete", this method will try to call
`self.process_delete_action(items)`
"""
method_name = f"process_{action}_action"
if hasattr(self, method_name):
getattr(self, method_name)(items)
[docs] def post(
self,
request: HttpRequest,
*args: Any, # noqa: ARG002
**kwargs: Any, # noqa: ARG002
) -> HttpResponseRedirect | Http404:
"""
Handle POST requests by processing the form action and redirecting.
This method:
1. Extracts the selected items and action from the POST data
2. Delegates to `process_form_action` for the actual processing
3. Redirects to the URL specified by the `url` attribute
Args:
request: The HTTP request object
*args: Additional positional arguments (not used)
**kwargs: Additional keyword arguments (not used)
Returns:
HttpResponseRedirect: Redirect to the specified URL after successful
processing
Http404: If the request doesn't include required POST data
Raises:
ImproperlyConfigured: If the `url` attribute is not set
"""
checkboxes = request.POST.getlist("checkbox")
action = request.POST.get("action")
if not action or not checkboxes:
msg = "POST request did not include the necessary fields"
raise Http404(msg)
self.process_form_action(action, checkboxes)
if not self.url:
msg = f"You must set a url attribute on {self.__class__.__name__}"
raise ImproperlyConfigured(msg)
return HttpResponseRedirect(self.url)
[docs]class TableView(TemplateView):
"""
A template view that renders a data table.
This view simplifies the common pattern of rendering a template that includes
a data table. It instantiates the specified table class and adds it to the
template context.
To use this view:
1. Subclass it and set the `table_class` attribute to your table class
2. Set `template_name` to the template that will render the table
Attributes:
table_class: The table widget class to instantiate and render
Example:
.. code-block:: python
from wildewidgets import TableView, BaseModelTable
from myapp.models import User
class UserTable(BaseModelTable):
model = User
fields: List[str] = ["username", "email", "date_joined"]
class UserTableView(TableView):
table_class = UserTable
"""
#: The table class to use for rendering the table.
table_class: type[BaseDataTable] | None = None
[docs] def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
"""
Add the instantiated table to the template context.
This method instantiates the table specified by `table_class` and adds
it to the template context with the key 'table'.
Args:
**kwargs: Additional context variables
Returns:
dict: The updated template context with the table instance
Raises:
ImproperlyConfigured: If `table_class` is not set
"""
if not self.table_class:
msg = f"You must set a table_class attribute on {self.__class__.__name__}"
raise ImproperlyConfigured(msg)
kwargs["table"] = self.table_class() # pylint: disable=not-callable
return super().get_context_data(**kwargs)