You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
86 lines
2.4 KiB
86 lines
2.4 KiB
import json
|
|
from typing import Any, Optional
|
|
|
|
from django import forms
|
|
from django.db import models
|
|
from django.utils.safestring import mark_safe
|
|
|
|
from django.forms import MultiWidget, Widget
|
|
|
|
|
|
JSON_EDITOR_CLASSES = [
|
|
"border",
|
|
"border-base-200",
|
|
"rounded",
|
|
"group-[.errors]:border-red-600",
|
|
"w-full",
|
|
"dark:border-base-700",
|
|
"dark:group-[.errors]:border-red-500",
|
|
]
|
|
|
|
|
|
class JsonEditorWidget(Widget):
|
|
template_name = 'account/json_editor_field.html'
|
|
|
|
class Media:
|
|
css = {
|
|
'all': ('https://cdn.jsdelivr.net/npm/@json-editor/json-editor@latest/dist/css/jsoneditor.min.css',)
|
|
}
|
|
js = ('https://cdn.jsdelivr.net/npm/@json-editor/json-editor@latest/dist/jsoneditor.min.js',)
|
|
|
|
def __init__(self, attrs: Optional[dict[str, Any]] = None) -> None:
|
|
if attrs is None:
|
|
attrs = {}
|
|
|
|
# Set default title if not provided
|
|
if 'title' not in attrs and 'label' in attrs:
|
|
attrs['title'] = attrs['label']
|
|
elif 'title' not in attrs:
|
|
attrs['title'] = 'JSON Editor'
|
|
|
|
super().__init__(attrs)
|
|
|
|
self.attrs.update({
|
|
'class': ' '.join(JSON_EDITOR_CLASSES),
|
|
})
|
|
|
|
def render(self, name, value, attrs=None, renderer=None):
|
|
if value is None:
|
|
value = '{}'
|
|
elif isinstance(value, dict):
|
|
value = json.dumps(value)
|
|
|
|
attrs = self.build_attrs(self.attrs, attrs)
|
|
attrs['name'] = name
|
|
|
|
# Ensure the schema is properly passed to the template
|
|
if 'schema' in self.attrs:
|
|
attrs['schema'] = self.attrs['schema']
|
|
|
|
# Pass field name as title if not set
|
|
if 'title' not in attrs:
|
|
attrs['title'] = name.replace('_', ' ').title()
|
|
|
|
return super().render(name, value, attrs, renderer)
|
|
|
|
|
|
class JsonEditorField(models.JSONField):
|
|
schema = {}
|
|
|
|
def __init__(self, *args, schema: dict, **kwargs):
|
|
self.schema = schema
|
|
super().__init__(*args, **kwargs)
|
|
|
|
def formfield(self, **kwargs):
|
|
schema = self.schema() if callable(self.schema) else self.schema
|
|
|
|
kwargs.update({
|
|
'widget': JsonEditorWidget(attrs={'schema': json.dumps(schema)}),
|
|
})
|
|
return super(JsonEditorField, self).formfield(**kwargs)
|
|
|
|
def deconstruct(self):
|
|
name, path, args, kwargs = super().deconstruct()
|
|
kwargs['schema'] = self.schema
|
|
|
|
return name, path, args, kwargs
|