> Please provide enough information so that others can review your pull request: Added json support for postgres and mariadb > Explain the **details** for making this change. What existing problem does the pull request solve? https://github.com/frappe/frappe/projects/4#card-50160428 > Screenshots/GIFs  --- **Previous attempts:** https://github.com/frappe/frappe/pull/8128 https://github.com/frappe/frappe/pull/7096 Docs: https://frappeframework.com/docs/v13/user/en/basics/doctypes/fieldtypes#jsonversion-14
@@ -99,7 +99,7 @@ | |||||
"label": "Type", | "label": "Type", | ||||
"oldfieldname": "fieldtype", | "oldfieldname": "fieldtype", | ||||
"oldfieldtype": "Select", | "oldfieldtype": "Select", | ||||
"options": "Autocomplete\nAttach\nAttach Image\nBarcode\nButton\nCheck\nCode\nColor\nColumn Break\nCurrency\nData\nDate\nDatetime\nDuration\nDynamic Link\nFloat\nFold\nGeolocation\nHeading\nHTML\nHTML Editor\nIcon\nImage\nInt\nLink\nLong Text\nMarkdown Editor\nPassword\nPercent\nRead Only\nRating\nSection Break\nSelect\nSignature\nSmall Text\nTab Break\nTable\nTable MultiSelect\nText\nText Editor\nTime", | |||||
"options": "Autocomplete\nAttach\nAttach Image\nBarcode\nButton\nCheck\nCode\nColor\nColumn Break\nCurrency\nData\nDate\nDatetime\nDuration\nDynamic Link\nFloat\nFold\nGeolocation\nHeading\nHTML\nHTML Editor\nIcon\nImage\nInt\nJSON\nLink\nLong Text\nMarkdown Editor\nPassword\nPercent\nRead Only\nRating\nSection Break\nSelect\nSignature\nSmall Text\nTab Break\nTable\nTable MultiSelect\nText\nText Editor\nTime", | |||||
"reqd": 1, | "reqd": 1, | ||||
"search_index": 1 | "search_index": 1 | ||||
}, | }, | ||||
@@ -547,7 +547,7 @@ | |||||
"index_web_pages_for_search": 1, | "index_web_pages_for_search": 1, | ||||
"istable": 1, | "istable": 1, | ||||
"links": [], | "links": [], | ||||
"modified": "2022-02-14 11:56:19.812863", | |||||
"modified": "2022-03-02 17:07:32.117897", | |||||
"modified_by": "Administrator", | "modified_by": "Administrator", | ||||
"module": "Core", | "module": "Core", | ||||
"name": "DocField", | "name": "DocField", | ||||
@@ -538,6 +538,35 @@ class TestDocType(unittest.TestCase): | |||||
# cleanup | # cleanup | ||||
dt.delete(ignore_permissions=True) | dt.delete(ignore_permissions=True) | ||||
def test_json_field(self): | |||||
"""Test json field.""" | |||||
import json | |||||
json_doc = new_doctype( | |||||
"Test Json Doctype", | |||||
fields=[{"label": "json field", "fieldname": "test_json_field", "fieldtype": "JSON"}], | |||||
) | |||||
json_doc.insert() | |||||
json_doc.save() | |||||
doc = frappe.get_doc("DocType", "Test Json Doctype") | |||||
for field in doc.fields: | |||||
if field.fieldname == "test_json_field": | |||||
self.assertEqual(field.fieldtype, "JSON") | |||||
break | |||||
doc = frappe.get_doc( | |||||
{"doctype": "Test Json Doctype", "test_json_field": json.dumps({"hello": "world"})} | |||||
) | |||||
doc.insert() | |||||
doc.save() | |||||
test_json = frappe.get_doc("Test Json Doctype", doc.name) | |||||
if isinstance(test_json.test_json_field, str): | |||||
test_json.test_json_field = json.loads(test_json.test_json_field) | |||||
self.assertEqual(test_json.test_json_field["hello"], "world") | |||||
def new_doctype( | def new_doctype( | ||||
name, unique: bool = False, depends_on: str = "", fields: Optional[List[Dict]] = None, **kwargs | name, unique: bool = False, depends_on: str = "", fields: Optional[List[Dict]] = None, **kwargs | ||||
@@ -54,6 +54,7 @@ class MariaDBDatabase(Database): | |||||
"Duration": ("decimal", "21,9"), | "Duration": ("decimal", "21,9"), | ||||
"Icon": ("varchar", self.VARCHAR_LEN), | "Icon": ("varchar", self.VARCHAR_LEN), | ||||
"Autocomplete": ("varchar", self.VARCHAR_LEN), | "Autocomplete": ("varchar", self.VARCHAR_LEN), | ||||
"JSON": ("json", ""), | |||||
} | } | ||||
def get_connection(self): | def get_connection(self): | ||||
@@ -66,6 +66,7 @@ class PostgresDatabase(Database): | |||||
"Duration": ("decimal", "21,9"), | "Duration": ("decimal", "21,9"), | ||||
"Icon": ("varchar", self.VARCHAR_LEN), | "Icon": ("varchar", self.VARCHAR_LEN), | ||||
"Autocomplete": ("varchar", self.VARCHAR_LEN), | "Autocomplete": ("varchar", self.VARCHAR_LEN), | ||||
"JSON": ("json", ""), | |||||
} | } | ||||
def get_connection(self): | def get_connection(self): | ||||
@@ -37,6 +37,7 @@ data_fieldtypes = ( | |||||
"Duration", | "Duration", | ||||
"Icon", | "Icon", | ||||
"Autocomplete", | "Autocomplete", | ||||
"JSON", | |||||
) | ) | ||||
attachment_fieldtypes = ( | attachment_fieldtypes = ( | ||||
@@ -1,6 +1,7 @@ | |||||
# Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors | # Copyright (c) 2022, Frappe Technologies Pvt. Ltd. and Contributors | ||||
# License: MIT. See LICENSE | # License: MIT. See LICENSE | ||||
import datetime | import datetime | ||||
import json | |||||
import frappe | import frappe | ||||
from frappe import _ | from frappe import _ | ||||
@@ -287,6 +288,9 @@ class BaseDocument(object): | |||||
elif df.fieldtype == "Int" and not isinstance(d[fieldname], int): | elif df.fieldtype == "Int" and not isinstance(d[fieldname], int): | ||||
d[fieldname] = cint(d[fieldname]) | d[fieldname] = cint(d[fieldname]) | ||||
elif df.fieldtype == "JSON" and isinstance(d[fieldname], dict): | |||||
d[fieldname] = json.dumps(d[fieldname], sort_keys=True, indent=4, separators=(",", ": ")) | |||||
elif df.fieldtype in ("Currency", "Float", "Percent") and not isinstance(d[fieldname], float): | elif df.fieldtype in ("Currency", "Float", "Percent") and not isinstance(d[fieldname], float): | ||||
d[fieldname] = flt(d[fieldname]) | d[fieldname] = flt(d[fieldname]) | ||||
@@ -39,6 +39,7 @@ import './multiselect_list'; | |||||
import './rating'; | import './rating'; | ||||
import './duration'; | import './duration'; | ||||
import './icon'; | import './icon'; | ||||
import './json'; | |||||
frappe.ui.form.make_control = function (opts) { | frappe.ui.form.make_control = function (opts) { | ||||
var control_class_name = "Control" + opts.df.fieldtype.replace(/ /g, ""); | var control_class_name = "Control" + opts.df.fieldtype.replace(/ /g, ""); | ||||
@@ -0,0 +1,6 @@ | |||||
frappe.ui.form.ControlJSON = class ControlCode extends frappe.ui.form.ControlCode { | |||||
set_language() { | |||||
this.editor.session.setMode('ace/mode/json'); | |||||
this.editor.setKeyboardHandler('ace/keyboard/vscode'); | |||||
} | |||||
}; |