from dataclasses import dataclass from django.contrib.sites.shortcuts import get_current_site as django_get_current_site from django.db.models import Model from django.http import HttpRequest from django.http import HttpResponse from django.urls import reverse from zen_queries import render def base_view_context(request): """Include the current site in the context.""" return {"site": django_get_current_site(request)} @dataclass class Row: """ A row in a table. """ data: dict[str, str] actions: list[dict[str, str]] @dataclass class RowAction: """ An action that can be performed on a row in a table. """ label: str url_name: str url_kwargs: dict[str, str] def render(self, obj) -> dict[str, str]: """ Render the action as a dictionary for the given object. """ url = reverse( self.url_name, kwargs={key: getattr(obj, value) for key, value in self.url_kwargs.items()}, ) return {"label": self.label, "url": url} def render_list( request: HttpRequest, objects: list["Model"], columns: list[tuple[str, str]], row_actions: list[RowAction] = None, list_actions: list[tuple[str, str]] = None, ) -> HttpResponse: """ Render a list of objects with a table. """ # TODO: List actions rows = [] for obj in objects: row = Row( data={column: getattr(obj, column[0]) for column in columns}, actions=[action.render(obj) for action in row_actions], ) rows.append(row) column_labels = [column[1] for column in columns] context = base_view_context(request) | { "rows": rows, "columns": column_labels, "row_actions": row_actions, "list_actions": list_actions, } return render( request=request, template_name="utils/list.html", context=context, )