Source code for ferrosoft.apps.ferrobase.tables.crud

#  Copyright (c) 2025 Ferrosoft GmbH. All rights reserved.
from dataclasses import dataclass

from django.utils.translation import gettext_lazy as _

from ferrosoft.apps.emiflow.widgets import EditDeleteActionsWidget
from ferrosoft.apps.ferrobase.tables.columns import WidgetColumn
from ferrosoft.apps.ferrobase.tables.table import Table


[docs] @dataclass class Action: """Extra header action exposed in the table template (label + URL).""" url: str label: str
[docs] class CRUDTable(Table): """Table preconfigured with create/update/delete affordances. Renders the "with add button" Bootstrap 5 template and an ``actions`` column containing per-row edit/delete buttons. The button URLs are resolved through :meth:`get_update_action_url` and :meth:`get_delete_action_url`, both of which subclasses are expected to override when they need custom routes. Passing ``disable_update=True`` on construction hides the actions column and the add button — useful for read-only views. Template context exposes ``actions``, ``create_label``, ``create_url`` and ``disable_update`` in addition to the base table context. """
[docs] class Meta: template_name = "ferrobase/bootstrap5/table/with_add_button.html" create_label = _("Add") create_url = None
actions = WidgetColumn( verbose_name=_("Actions"), widget=EditDeleteActionsWidget(), ) def __init__(self, *args, **kwargs): """Capture the CRUD-specific kwargs and wire URL resolvers.""" self._create_label = kwargs.pop( "create_label", getattr(self.Meta, "create_label", _("Add")) ) self._create_url = kwargs.pop( "create_url", getattr(self.Meta, "create_url", None) ) self._actions: list[Action] = kwargs.pop("actions", []) self._disable_update = kwargs.pop("disable_update", False) super().__init__(*args, **kwargs) # Setting protected members here because of self binding issues when # referencing in class body. # # noinspection PyProtectedMember self.columns["actions"].column.widget._delete_url = self.get_delete_action_url # noinspection PyProtectedMember self.columns["actions"].column.widget._edit_url = self.get_update_action_url
[docs] def before_render(self, request): """Hide the ``actions`` column when constructed with ``disable_update``.""" if self._disable_update and "actions" in self.columns: self.columns.hide("actions")
[docs] def get_delete_action_url(self, *args, **kwargs) -> str | None: """Return the delete URL for ``kwargs['record']`` or ``None`` (default).""" return None
[docs] def get_update_action_url(self, *args, **kwargs) -> str | None: """Return the row's ``get_absolute_url()`` if the model defines one.""" record = kwargs.get("record") if hasattr(record, "get_absolute_url"): return record.get_absolute_url() return None
[docs] def template_context(self, request): """Augment base template context with CRUD-specific keys.""" return super().template_context(request) | { "actions": self._actions, "create_label": self._create_label, "create_url": self._create_url, "disable_update": self._disable_update, }