fields.py
2.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
from django import forms
from django.core.serializers.json import DjangoJSONEncoder
from django.db import models
from django.db.backends.base.base import BaseDatabaseWrapper
from simplejson import JSONDecodeError
from typing import Any, Dict, Optional, Union
import simplejson
__all__ = ['JSONField', 'JsonFormWidget']
class JsonFormWidget(forms.Textarea):
template_name = 'comments/json_field_widget.html'
def get_context(self, name: str, value: Any, attrs: Optional[Dict]) -> Dict[str, Any]:
ctx = super().get_context(name, value, attrs)
ctx['widget']['json_value'] = simplejson.dumps(value)
return ctx
class Media:
js = [
'https://cdnjs.cloudflare.com/ajax/libs/jsoneditor/8.6.3/jsoneditor.js',
'base_model_s/widgets/json_editor{min}.js',
]
css = {
'all': [
'https://cdnjs.cloudflare.com/ajax/libs/jsoneditor/8.6.3/jsoneditor.min.css',
]
}
class JSONField(models.TextField):
def formfield(self, **kwargs: Any) -> forms.Field:
kwargs.setdefault('widget', JsonFormWidget)
return super().formfield(**kwargs)
@staticmethod
def _get_json_value(value: str) -> Optional[Union[dict, list]]:
if not value:
return None
if isinstance(value, list):
return value
try:
return simplejson.loads(value)
except JSONDecodeError:
return {'data': str(value)}
def from_db_value(self, value: Any, expression, connection: BaseDatabaseWrapper) -> Any:
return self._get_json_value(value)
def pre_save(self, model_instance: models.Model, add: bool) -> str:
""" Convert Python to Json format before save in database """
value = super().pre_save(model_instance, add)
if isinstance(value, str):
return value
return simplejson.dumps(value, cls=DjangoJSONEncoder)
def clean(self, value, model_instance):
"""
Convert the value's type and run validation. Validation errors
from _get_json_value() and validate() are propagated. Return the correct
value if no error is raised.
"""
value = self._get_json_value(value)
self.validate(value, model_instance)
self.run_validators(value)
return value