import json from typing import Any, Mapping from django import forms from django.core.files.uploadedfile import UploadedFile from django.forms.renderers import BaseRenderer from django.utils.datastructures import MultiValueDict from django.utils.safestring import SafeString class JSONTableWidget(forms.Widget): template_name = "json_table_widget.html" def format_value(self, value: str | dict[str, Any]) -> str | dict[str, Any]: # ty: ignore[invalid-method-override] if isinstance(value, dict): return value try: if isinstance(value, str): value = json.loads(value) except json.JSONDecodeError: value = {} return value def render( self, name: str, value: str | dict[str, Any], attrs: dict[str, Any] | None = None, renderer: BaseRenderer | None = None, ) -> SafeString: value = self.format_value(value) return super().render(name, value, attrs, renderer) def value_from_datadict( self, data: Mapping[str, Any], files: MultiValueDict[str, UploadedFile], name: str, ) -> str | None: json_data = {} try: keys = data.getlist(f"{name}_key") # ty: ignore[unresolved-attribute] values = data.getlist(f"{name}_value") # ty: ignore[unresolved-attribute] for key, value in zip(keys, values, strict=True): if key.strip(): try: json_data[key] = json.loads(value) except (json.JSONDecodeError, ValueError): json_data[key] = value except TypeError: pass return None if not json_data else json.dumps(json_data)