84 lines
2.4 KiB
Python
84 lines
2.4 KiB
Python
from django.db import models
|
|
from django.forms import fields
|
|
|
|
from asyncron.widgets import Codearea
|
|
|
|
import tomlkit
|
|
from tomlkit.exceptions import ParseError
|
|
from tomlkit.toml_document import TOMLDocument
|
|
|
|
|
|
class InvalidTOMLInput(str):
|
|
pass
|
|
|
|
class TOMLFormField( fields.JSONField ):
|
|
default_error_messages = {
|
|
"invalid": "Enter a valid TOML.",
|
|
}
|
|
|
|
widget = Codearea( language = "ini" )
|
|
|
|
def to_python(self, value):
|
|
if self.disabled: return value
|
|
if isinstance(value, (list, dict, int, float)): return value
|
|
|
|
try:
|
|
converted = tomlkit.loads( value )
|
|
except ParseError:
|
|
raise ValidationError(
|
|
self.error_messages["invalid"],
|
|
code="invalid",
|
|
params={"value": value},
|
|
)
|
|
return converted
|
|
|
|
|
|
def bound_data(self, data, initial):
|
|
if self.disabled: return initial
|
|
if data is None: return None
|
|
|
|
try:
|
|
return tomlkit.loads( data )
|
|
except ParseError:
|
|
return InvalidTOMLInput(data)
|
|
|
|
def prepare_value(self, value):
|
|
if isinstance(value, InvalidTOMLInput): return value
|
|
return value.as_string()
|
|
|
|
|
|
|
|
class TOMLField( models.JSONField ):
|
|
empty_strings_allowed = True
|
|
description = "A TOML Field"
|
|
|
|
def from_db_value(self, *args, **kwargs):
|
|
value_as_dict = super().from_db_value(*args, **kwargs)
|
|
|
|
#This is a cop-out, but I don't have time to do this properly even though it's very interesting.
|
|
#But duplicating the date on fields that are meant to be human readable, isn't a serious problem.
|
|
#
|
|
# Links to related parts of tomlkit in case I decide to improve on this later:
|
|
# - as_string function which decies which renderer to choose
|
|
# - https://github.com/python-poetry/tomlkit/blob/6042e0ce80c8c49f325a6e60b6ee3e153669b144/tomlkit/container.py#L485
|
|
#
|
|
# - The simple renderer which has the item.as_string bit that we have to optimize out.
|
|
# - https://github.com/python-poetry/tomlkit/blob/6042e0ce80c8c49f325a6e60b6ee3e153669b144/tomlkit/container.py#L633
|
|
#
|
|
try: value_as_toml = tomlkit.loads( value_as_dict.pop('_toml', '') )
|
|
except: value_as_toml = tomlkit.document()
|
|
value_as_toml.update( value_as_dict )
|
|
|
|
return value_as_toml
|
|
|
|
def get_prep_value(self, *args, **kwargs):
|
|
result = super().get_prep_value( *args, **kwargs )
|
|
if not isinstance( result, TOMLDocument ): return result
|
|
as_dict = result.unwrap()
|
|
as_dict['_toml'] = result.as_string()
|
|
return as_dict
|
|
|
|
def formfield( self, *args, **kwargs ):
|
|
kwargs['form_class'] = TOMLFormField
|
|
return super().formfield(*args, **kwargs)
|