We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
SQL SyntaxError in queries in DocTypes with Table Multiselect fields
### App Versions
```json
{
	"frappe": "15.0.0-dev"
}
```
### Route

`List/User Group/List` and `Form/User Group/new-user-group-1`

### Traceback

```python
Syntax error in query:
select distinct 
			from `tabUser Group` 
Traceback (most recent call last):
  File "apps/frappe/frappe/app.py", line 53, in application
    response = frappe.api.handle()
  File "apps/frappe/frappe/api.py", line 53, in handle
    return _RESTAPIHandler(call, doctype, name).get_response()
  File "apps/frappe/frappe/api.py", line 69, in get_response
    return self.handle_method()
  File "apps/frappe/frappe/api.py", line 79, in handle_method
    return frappe.handler.handle()
  File "apps/frappe/frappe/handler.py", line 48, in handle
    data = execute_cmd(cmd)
  File "apps/frappe/frappe/handler.py", line 86, in execute_cmd
    return frappe.call(method, **frappe.form_dict)
  File "apps/frappe/frappe/__init__.py", line 1591, in call
    return fn(*args, **newargs)
  File "apps/frappe/frappe/utils/typing_validations.py", line 33, in wrapper
    return func(*args, **kwargs)
  File "apps/frappe/frappe/__init__.py", line 796, in wrapper_fn
    retval = fn(*args, **get_newargs(fn, kwargs))
  File "apps/frappe/frappe/desk/reportview.py", line 58, in get_count
    data = execute(**args)[0].get("total_count")
  File "apps/frappe/frappe/desk/reportview.py", line 64, in execute
    return DatabaseQuery(doctype).execute(*args, **kwargs)
  File "apps/frappe/frappe/model/db_query.py", line 202, in execute
    result = self.build_and_run()
  File "apps/frappe/frappe/model/db_query.py", line 242, in build_and_run
    return frappe.db.sql(
  File "apps/frappe/frappe/database/database.py", line 222, in sql
    self._cursor.execute(query, values)
  File "env/lib/python3.10/site-packages/pymysql/cursors.py", line 148, in execute
    result = self._query(query)
  File "env/lib/python3.10/site-packages/pymysql/cursors.py", line 310, in _query
    conn.query(q)
  File "env/lib/python3.10/site-packages/pymysql/connections.py", line 548, in query
    self._affected_rows = self._read_query_result(unbuffered=unbuffered)
  File "env/lib/python3.10/site-packages/pymysql/connections.py", line 775, in _read_query_result
    result.read()
  File "env/lib/python3.10/site-packages/pymysql/connections.py", line 1156, in read
    first_packet = self.connection._read_packet()
  File "env/lib/python3.10/site-packages/pymysql/connections.py", line 725, in _read_packet
    packet.raise_for_error()
  File "env/lib/python3.10/site-packages/pymysql/protocol.py", line 221, in raise_for_error
    err.raise_mysql_exception(self._data)
  File "env/lib/python3.10/site-packages/pymysql/err.py", line 143, in raise_mysql_exception
    raise errorclass(errno, errval)
pymysql.err.ProgrammingError: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'from `tabUser Group`' at line 2")

```
### Request Data

```json
{
	"type": "POST",
	"args": {
		"doctype": "User Group",
		"filters": "[]",
		"fields": "[]",
		"distinct": false
	},
	"headers": {},
	"error_handlers": {},
	"url": "/api/method/frappe.desk.reportview.get_count"
}
```
### Response Data

```json
{
	"exception": "pymysql.err.ProgrammingError: (1064, \"You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'from `tabUser Group`' at line 2\")",
	"_debug_messages": "[\"method:frappe.desk.reportview.get_count\", \"<<<< query\\nSELECT `is_virtual` FROM `tabDocType` WHERE `name`='User Group' ORDER BY `modified` DESC LIMIT 1\\n>>>>\", \"<<<< query\\nselect `share_name`\\n\\t\\t\\tfrom `tabDocShare`\\n\\t\\t\\twhere `tabDocShare`.`read` = 1.0 and `tabDocShare`.`share_doctype` = 'User Group' and (`tabDocShare`.`user` = 'Administrator' or `tabDocShare`.`everyone` = 1.0)\\n\\t\\t\\t\\n\\t\\t\\t order by `tabDocShare`.`modified` DESC\\n>>>>\"]"
}
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `frappe/model/__init__.py`
Content:
```
1 # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
2 # License: MIT. See LICENSE
3 
4 # model __init__.py
5 import frappe
6 
7 data_fieldtypes = (
8 	"Currency",
9 	"Int",
10 	"Long Int",
11 	"Float",
12 	"Percent",
13 	"Check",
14 	"Small Text",
15 	"Long Text",
16 	"Code",
17 	"Text Editor",
18 	"Markdown Editor",
19 	"HTML Editor",
20 	"Date",
21 	"Datetime",
22 	"Time",
23 	"Text",
24 	"Data",
25 	"Link",
26 	"Dynamic Link",
27 	"Password",
28 	"Select",
29 	"Rating",
30 	"Read Only",
31 	"Attach",
32 	"Attach Image",
33 	"Signature",
34 	"Color",
35 	"Barcode",
36 	"Geolocation",
37 	"Duration",
38 	"Icon",
39 	"Phone",
40 	"Autocomplete",
41 	"JSON",
42 )
43 
44 float_like_fields = {"Float", "Currency", "Percent"}
45 datetime_fields = {"Datetime", "Date", "Time"}
46 
47 attachment_fieldtypes = (
48 	"Attach",
49 	"Attach Image",
50 )
51 
52 no_value_fields = (
53 	"Section Break",
54 	"Column Break",
55 	"Tab Break",
56 	"HTML",
57 	"Table",
58 	"Table MultiSelect",
59 	"Button",
60 	"Image",
61 	"Fold",
62 	"Heading",
63 )
64 
65 display_fieldtypes = (
66 	"Section Break",
67 	"Column Break",
68 	"Tab Break",
69 	"HTML",
70 	"Button",
71 	"Image",
72 	"Fold",
73 	"Heading",
74 )
75 
76 numeric_fieldtypes = ("Currency", "Int", "Long Int", "Float", "Percent", "Check")
77 
78 data_field_options = ("Email", "Name", "Phone", "URL", "Barcode")
79 
80 default_fields = (
81 	"doctype",
82 	"name",
83 	"owner",
84 	"creation",
85 	"modified",
86 	"modified_by",
87 	"docstatus",
88 	"idx",
89 )
90 
91 child_table_fields = ("parent", "parentfield", "parenttype")
92 
93 optional_fields = ("_user_tags", "_comments", "_assign", "_liked_by", "_seen")
94 
95 table_fields = ("Table", "Table MultiSelect")
96 
97 core_doctypes_list = (
98 	"DefaultValue",
99 	"DocType",
100 	"DocField",
101 	"DocPerm",
102 	"DocType Action",
103 	"DocType Link",
104 	"User",
105 	"Role",
106 	"Has Role",
107 	"Page",
108 	"Module Def",
109 	"Print Format",
110 	"Report",
111 	"Customize Form",
112 	"Customize Form Field",
113 	"Property Setter",
114 	"Custom Field",
115 	"Client Script",
116 )
117 
118 # NOTE: this is being used for dynamic autoincrement in new sites,
119 # removing any of these will require patches.
120 log_types = (
121 	"Version",
122 	"Error Log",
123 	"Scheduled Job Log",
124 	"Event Sync Log",
125 	"Event Update Log",
126 	"Access Log",
127 	"View Log",
128 	"Activity Log",
129 	"Energy Point Log",
130 	"Notification Log",
131 	"Email Queue",
132 	"DocShare",
133 	"Document Follow",
134 	"Console Log",
135 )
136 
137 
138 def delete_fields(args_dict, delete=0):
139 	"""
140 	Delete a field.
141 	* Deletes record from `tabDocField`
142 	* If not single doctype: Drops column from table
143 	* If single, deletes record from `tabSingles`
144 	args_dict = { dt: [field names] }
145 	"""
146 	import frappe.utils
147 
148 	for dt in args_dict:
149 		fields = args_dict[dt]
150 		if not fields:
151 			continue
152 
153 		frappe.db.delete(
154 			"DocField",
155 			{
156 				"parent": dt,
157 				"fieldname": ("in", fields),
158 			},
159 		)
160 
161 		# Delete the data/column only if delete is specified
162 		if not delete:
163 			continue
164 
165 		if frappe.db.get_value("DocType", dt, "issingle"):
166 			frappe.db.delete(
167 				"Singles",
168 				{
169 					"doctype": dt,
170 					"field": ("in", fields),
171 				},
172 			)
173 		else:
174 			existing_fields = frappe.db.describe(dt)
175 			existing_fields = existing_fields and [e[0] for e in existing_fields] or []
176 			fields_need_to_delete = set(fields) & set(existing_fields)
177 			if not fields_need_to_delete:
178 				continue
179 
180 			if frappe.db.db_type == "mariadb":
181 				# mariadb implicitly commits before DDL, make it explicit
182 				frappe.db.commit()
183 
184 			query = "ALTER TABLE `tab%s` " % dt + ", ".join(
185 				"DROP COLUMN `%s`" % f for f in fields_need_to_delete
186 			)
187 			frappe.db.sql(query)
188 
189 		if frappe.db.db_type == "postgres":
190 			# commit the results to db
191 			frappe.db.commit()
192 
193 
194 def get_permitted_fields(
195 	doctype: str, parenttype: str | None = None, user: str | None = None
196 ) -> list[str]:
197 	meta = frappe.get_meta(doctype)
198 	valid_columns = meta.get_valid_columns()
199 
200 	if doctype in core_doctypes_list:
201 		return valid_columns
202 
203 	if permitted_fields := meta.get_permitted_fieldnames(parenttype=parenttype, user=user):
204 		meta_fields = meta.default_fields.copy()
205 		optional_meta_fields = [x for x in optional_fields if x in valid_columns]
206 
207 		if meta.istable:
208 			meta_fields.extend(child_table_fields)
209 
210 		return meta_fields + permitted_fields + optional_meta_fields
211 
212 	return []
213
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/frappe/model/__init__.py b/frappe/model/__init__.py
--- a/frappe/model/__init__.py
+++ b/frappe/model/__init__.py
@@ -200,6 +200,10 @@
 	if doctype in core_doctypes_list:
 		return valid_columns
 
+	# DocType has only fields of type Table (Table, Table MultiSelect)
+	if set(valid_columns).issubset(default_fields):
+		return valid_columns
+
 	if permitted_fields := meta.get_permitted_fieldnames(parenttype=parenttype, user=user):
 		meta_fields = meta.default_fields.copy()
 		optional_meta_fields = [x for x in optional_fields if x in valid_columns]

{"golden_diff": "diff --git a/frappe/model/__init__.py b/frappe/model/__init__.py\n--- a/frappe/model/__init__.py\n+++ b/frappe/model/__init__.py\n@@ -200,6 +200,10 @@\n \tif doctype in core_doctypes_list:\n \t\treturn valid_columns\n \n+\t# DocType has only fields of type Table (Table, Table MultiSelect)\n+\tif set(valid_columns).issubset(default_fields):\n+\t\treturn valid_columns\n+\n \tif permitted_fields := meta.get_permitted_fieldnames(parenttype=parenttype, user=user):\n \t\tmeta_fields = meta.default_fields.copy()\n \t\toptional_meta_fields = [x for x in optional_fields if x in valid_columns]\n", "issue": "SQL SyntaxError in queries in DocTypes with Table Multiselect fields\n### App Versions\r\n```json\r\n{\r\n\t\"frappe\": \"15.0.0-dev\"\r\n}\r\n```\r\n### Route\r\n\r\n`List/User Group/List` and `Form/User Group/new-user-group-1`\r\n\r\n### Traceback\r\n\r\n```python\r\nSyntax error in query:\r\nselect distinct \r\n\t\t\tfrom `tabUser Group` \r\nTraceback (most recent call last):\r\n  File \"apps/frappe/frappe/app.py\", line 53, in application\r\n    response = frappe.api.handle()\r\n  File \"apps/frappe/frappe/api.py\", line 53, in handle\r\n    return _RESTAPIHandler(call, doctype, name).get_response()\r\n  File \"apps/frappe/frappe/api.py\", line 69, in get_response\r\n    return self.handle_method()\r\n  File \"apps/frappe/frappe/api.py\", line 79, in handle_method\r\n    return frappe.handler.handle()\r\n  File \"apps/frappe/frappe/handler.py\", line 48, in handle\r\n    data = execute_cmd(cmd)\r\n  File \"apps/frappe/frappe/handler.py\", line 86, in execute_cmd\r\n    return frappe.call(method, **frappe.form_dict)\r\n  File \"apps/frappe/frappe/__init__.py\", line 1591, in call\r\n    return fn(*args, **newargs)\r\n  File \"apps/frappe/frappe/utils/typing_validations.py\", line 33, in wrapper\r\n    return func(*args, **kwargs)\r\n  File \"apps/frappe/frappe/__init__.py\", line 796, in wrapper_fn\r\n    retval = fn(*args, **get_newargs(fn, kwargs))\r\n  File \"apps/frappe/frappe/desk/reportview.py\", line 58, in get_count\r\n    data = execute(**args)[0].get(\"total_count\")\r\n  File \"apps/frappe/frappe/desk/reportview.py\", line 64, in execute\r\n    return DatabaseQuery(doctype).execute(*args, **kwargs)\r\n  File \"apps/frappe/frappe/model/db_query.py\", line 202, in execute\r\n    result = self.build_and_run()\r\n  File \"apps/frappe/frappe/model/db_query.py\", line 242, in build_and_run\r\n    return frappe.db.sql(\r\n  File \"apps/frappe/frappe/database/database.py\", line 222, in sql\r\n    self._cursor.execute(query, values)\r\n  File \"env/lib/python3.10/site-packages/pymysql/cursors.py\", line 148, in execute\r\n    result = self._query(query)\r\n  File \"env/lib/python3.10/site-packages/pymysql/cursors.py\", line 310, in _query\r\n    conn.query(q)\r\n  File \"env/lib/python3.10/site-packages/pymysql/connections.py\", line 548, in query\r\n    self._affected_rows = self._read_query_result(unbuffered=unbuffered)\r\n  File \"env/lib/python3.10/site-packages/pymysql/connections.py\", line 775, in _read_query_result\r\n    result.read()\r\n  File \"env/lib/python3.10/site-packages/pymysql/connections.py\", line 1156, in read\r\n    first_packet = self.connection._read_packet()\r\n  File \"env/lib/python3.10/site-packages/pymysql/connections.py\", line 725, in _read_packet\r\n    packet.raise_for_error()\r\n  File \"env/lib/python3.10/site-packages/pymysql/protocol.py\", line 221, in raise_for_error\r\n    err.raise_mysql_exception(self._data)\r\n  File \"env/lib/python3.10/site-packages/pymysql/err.py\", line 143, in raise_mysql_exception\r\n    raise errorclass(errno, errval)\r\npymysql.err.ProgrammingError: (1064, \"You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'from `tabUser Group`' at line 2\")\r\n\r\n```\r\n### Request Data\r\n\r\n```json\r\n{\r\n\t\"type\": \"POST\",\r\n\t\"args\": {\r\n\t\t\"doctype\": \"User Group\",\r\n\t\t\"filters\": \"[]\",\r\n\t\t\"fields\": \"[]\",\r\n\t\t\"distinct\": false\r\n\t},\r\n\t\"headers\": {},\r\n\t\"error_handlers\": {},\r\n\t\"url\": \"/api/method/frappe.desk.reportview.get_count\"\r\n}\r\n```\r\n### Response Data\r\n\r\n```json\r\n{\r\n\t\"exception\": \"pymysql.err.ProgrammingError: (1064, \\\"You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'from `tabUser Group`' at line 2\\\")\",\r\n\t\"_debug_messages\": \"[\\\"method:frappe.desk.reportview.get_count\\\", \\\"<<<< query\\\\nSELECT `is_virtual` FROM `tabDocType` WHERE `name`='User Group' ORDER BY `modified` DESC LIMIT 1\\\\n>>>>\\\", \\\"<<<< query\\\\nselect `share_name`\\\\n\\\\t\\\\t\\\\tfrom `tabDocShare`\\\\n\\\\t\\\\t\\\\twhere `tabDocShare`.`read` = 1.0 and `tabDocShare`.`share_doctype` = 'User Group' and (`tabDocShare`.`user` = 'Administrator' or `tabDocShare`.`everyone` = 1.0)\\\\n\\\\t\\\\t\\\\t\\\\n\\\\t\\\\t\\\\t order by `tabDocShare`.`modified` DESC\\\\n>>>>\\\"]\"\r\n}\r\n```\n", "before_files": [{"content": "# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors\n# License: MIT. See LICENSE\n\n# model __init__.py\nimport frappe\n\ndata_fieldtypes = (\n\t\"Currency\",\n\t\"Int\",\n\t\"Long Int\",\n\t\"Float\",\n\t\"Percent\",\n\t\"Check\",\n\t\"Small Text\",\n\t\"Long Text\",\n\t\"Code\",\n\t\"Text Editor\",\n\t\"Markdown Editor\",\n\t\"HTML Editor\",\n\t\"Date\",\n\t\"Datetime\",\n\t\"Time\",\n\t\"Text\",\n\t\"Data\",\n\t\"Link\",\n\t\"Dynamic Link\",\n\t\"Password\",\n\t\"Select\",\n\t\"Rating\",\n\t\"Read Only\",\n\t\"Attach\",\n\t\"Attach Image\",\n\t\"Signature\",\n\t\"Color\",\n\t\"Barcode\",\n\t\"Geolocation\",\n\t\"Duration\",\n\t\"Icon\",\n\t\"Phone\",\n\t\"Autocomplete\",\n\t\"JSON\",\n)\n\nfloat_like_fields = {\"Float\", \"Currency\", \"Percent\"}\ndatetime_fields = {\"Datetime\", \"Date\", \"Time\"}\n\nattachment_fieldtypes = (\n\t\"Attach\",\n\t\"Attach Image\",\n)\n\nno_value_fields = (\n\t\"Section Break\",\n\t\"Column Break\",\n\t\"Tab Break\",\n\t\"HTML\",\n\t\"Table\",\n\t\"Table MultiSelect\",\n\t\"Button\",\n\t\"Image\",\n\t\"Fold\",\n\t\"Heading\",\n)\n\ndisplay_fieldtypes = (\n\t\"Section Break\",\n\t\"Column Break\",\n\t\"Tab Break\",\n\t\"HTML\",\n\t\"Button\",\n\t\"Image\",\n\t\"Fold\",\n\t\"Heading\",\n)\n\nnumeric_fieldtypes = (\"Currency\", \"Int\", \"Long Int\", \"Float\", \"Percent\", \"Check\")\n\ndata_field_options = (\"Email\", \"Name\", \"Phone\", \"URL\", \"Barcode\")\n\ndefault_fields = (\n\t\"doctype\",\n\t\"name\",\n\t\"owner\",\n\t\"creation\",\n\t\"modified\",\n\t\"modified_by\",\n\t\"docstatus\",\n\t\"idx\",\n)\n\nchild_table_fields = (\"parent\", \"parentfield\", \"parenttype\")\n\noptional_fields = (\"_user_tags\", \"_comments\", \"_assign\", \"_liked_by\", \"_seen\")\n\ntable_fields = (\"Table\", \"Table MultiSelect\")\n\ncore_doctypes_list = (\n\t\"DefaultValue\",\n\t\"DocType\",\n\t\"DocField\",\n\t\"DocPerm\",\n\t\"DocType Action\",\n\t\"DocType Link\",\n\t\"User\",\n\t\"Role\",\n\t\"Has Role\",\n\t\"Page\",\n\t\"Module Def\",\n\t\"Print Format\",\n\t\"Report\",\n\t\"Customize Form\",\n\t\"Customize Form Field\",\n\t\"Property Setter\",\n\t\"Custom Field\",\n\t\"Client Script\",\n)\n\n# NOTE: this is being used for dynamic autoincrement in new sites,\n# removing any of these will require patches.\nlog_types = (\n\t\"Version\",\n\t\"Error Log\",\n\t\"Scheduled Job Log\",\n\t\"Event Sync Log\",\n\t\"Event Update Log\",\n\t\"Access Log\",\n\t\"View Log\",\n\t\"Activity Log\",\n\t\"Energy Point Log\",\n\t\"Notification Log\",\n\t\"Email Queue\",\n\t\"DocShare\",\n\t\"Document Follow\",\n\t\"Console Log\",\n)\n\n\ndef delete_fields(args_dict, delete=0):\n\t\"\"\"\n\tDelete a field.\n\t* Deletes record from `tabDocField`\n\t* If not single doctype: Drops column from table\n\t* If single, deletes record from `tabSingles`\n\targs_dict = { dt: [field names] }\n\t\"\"\"\n\timport frappe.utils\n\n\tfor dt in args_dict:\n\t\tfields = args_dict[dt]\n\t\tif not fields:\n\t\t\tcontinue\n\n\t\tfrappe.db.delete(\n\t\t\t\"DocField\",\n\t\t\t{\n\t\t\t\t\"parent\": dt,\n\t\t\t\t\"fieldname\": (\"in\", fields),\n\t\t\t},\n\t\t)\n\n\t\t# Delete the data/column only if delete is specified\n\t\tif not delete:\n\t\t\tcontinue\n\n\t\tif frappe.db.get_value(\"DocType\", dt, \"issingle\"):\n\t\t\tfrappe.db.delete(\n\t\t\t\t\"Singles\",\n\t\t\t\t{\n\t\t\t\t\t\"doctype\": dt,\n\t\t\t\t\t\"field\": (\"in\", fields),\n\t\t\t\t},\n\t\t\t)\n\t\telse:\n\t\t\texisting_fields = frappe.db.describe(dt)\n\t\t\texisting_fields = existing_fields and [e[0] for e in existing_fields] or []\n\t\t\tfields_need_to_delete = set(fields) & set(existing_fields)\n\t\t\tif not fields_need_to_delete:\n\t\t\t\tcontinue\n\n\t\t\tif frappe.db.db_type == \"mariadb\":\n\t\t\t\t# mariadb implicitly commits before DDL, make it explicit\n\t\t\t\tfrappe.db.commit()\n\n\t\t\tquery = \"ALTER TABLE `tab%s` \" % dt + \", \".join(\n\t\t\t\t\"DROP COLUMN `%s`\" % f for f in fields_need_to_delete\n\t\t\t)\n\t\t\tfrappe.db.sql(query)\n\n\t\tif frappe.db.db_type == \"postgres\":\n\t\t\t# commit the results to db\n\t\t\tfrappe.db.commit()\n\n\ndef get_permitted_fields(\n\tdoctype: str, parenttype: str | None = None, user: str | None = None\n) -> list[str]:\n\tmeta = frappe.get_meta(doctype)\n\tvalid_columns = meta.get_valid_columns()\n\n\tif doctype in core_doctypes_list:\n\t\treturn valid_columns\n\n\tif permitted_fields := meta.get_permitted_fieldnames(parenttype=parenttype, user=user):\n\t\tmeta_fields = meta.default_fields.copy()\n\t\toptional_meta_fields = [x for x in optional_fields if x in valid_columns]\n\n\t\tif meta.istable:\n\t\t\tmeta_fields.extend(child_table_fields)\n\n\t\treturn meta_fields + permitted_fields + optional_meta_fields\n\n\treturn []\n", "path": "frappe/model/__init__.py"}], "after_files": [{"content": "# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors\n# License: MIT. See LICENSE\n\n# model __init__.py\nimport frappe\n\ndata_fieldtypes = (\n\t\"Currency\",\n\t\"Int\",\n\t\"Long Int\",\n\t\"Float\",\n\t\"Percent\",\n\t\"Check\",\n\t\"Small Text\",\n\t\"Long Text\",\n\t\"Code\",\n\t\"Text Editor\",\n\t\"Markdown Editor\",\n\t\"HTML Editor\",\n\t\"Date\",\n\t\"Datetime\",\n\t\"Time\",\n\t\"Text\",\n\t\"Data\",\n\t\"Link\",\n\t\"Dynamic Link\",\n\t\"Password\",\n\t\"Select\",\n\t\"Rating\",\n\t\"Read Only\",\n\t\"Attach\",\n\t\"Attach Image\",\n\t\"Signature\",\n\t\"Color\",\n\t\"Barcode\",\n\t\"Geolocation\",\n\t\"Duration\",\n\t\"Icon\",\n\t\"Phone\",\n\t\"Autocomplete\",\n\t\"JSON\",\n)\n\nfloat_like_fields = {\"Float\", \"Currency\", \"Percent\"}\ndatetime_fields = {\"Datetime\", \"Date\", \"Time\"}\n\nattachment_fieldtypes = (\n\t\"Attach\",\n\t\"Attach Image\",\n)\n\nno_value_fields = (\n\t\"Section Break\",\n\t\"Column Break\",\n\t\"Tab Break\",\n\t\"HTML\",\n\t\"Table\",\n\t\"Table MultiSelect\",\n\t\"Button\",\n\t\"Image\",\n\t\"Fold\",\n\t\"Heading\",\n)\n\ndisplay_fieldtypes = (\n\t\"Section Break\",\n\t\"Column Break\",\n\t\"Tab Break\",\n\t\"HTML\",\n\t\"Button\",\n\t\"Image\",\n\t\"Fold\",\n\t\"Heading\",\n)\n\nnumeric_fieldtypes = (\"Currency\", \"Int\", \"Long Int\", \"Float\", \"Percent\", \"Check\")\n\ndata_field_options = (\"Email\", \"Name\", \"Phone\", \"URL\", \"Barcode\")\n\ndefault_fields = (\n\t\"doctype\",\n\t\"name\",\n\t\"owner\",\n\t\"creation\",\n\t\"modified\",\n\t\"modified_by\",\n\t\"docstatus\",\n\t\"idx\",\n)\n\nchild_table_fields = (\"parent\", \"parentfield\", \"parenttype\")\n\noptional_fields = (\"_user_tags\", \"_comments\", \"_assign\", \"_liked_by\", \"_seen\")\n\ntable_fields = (\"Table\", \"Table MultiSelect\")\n\ncore_doctypes_list = (\n\t\"DefaultValue\",\n\t\"DocType\",\n\t\"DocField\",\n\t\"DocPerm\",\n\t\"DocType Action\",\n\t\"DocType Link\",\n\t\"User\",\n\t\"Role\",\n\t\"Has Role\",\n\t\"Page\",\n\t\"Module Def\",\n\t\"Print Format\",\n\t\"Report\",\n\t\"Customize Form\",\n\t\"Customize Form Field\",\n\t\"Property Setter\",\n\t\"Custom Field\",\n\t\"Client Script\",\n)\n\n# NOTE: this is being used for dynamic autoincrement in new sites,\n# removing any of these will require patches.\nlog_types = (\n\t\"Version\",\n\t\"Error Log\",\n\t\"Scheduled Job Log\",\n\t\"Event Sync Log\",\n\t\"Event Update Log\",\n\t\"Access Log\",\n\t\"View Log\",\n\t\"Activity Log\",\n\t\"Energy Point Log\",\n\t\"Notification Log\",\n\t\"Email Queue\",\n\t\"DocShare\",\n\t\"Document Follow\",\n\t\"Console Log\",\n)\n\n\ndef delete_fields(args_dict, delete=0):\n\t\"\"\"\n\tDelete a field.\n\t* Deletes record from `tabDocField`\n\t* If not single doctype: Drops column from table\n\t* If single, deletes record from `tabSingles`\n\targs_dict = { dt: [field names] }\n\t\"\"\"\n\timport frappe.utils\n\n\tfor dt in args_dict:\n\t\tfields = args_dict[dt]\n\t\tif not fields:\n\t\t\tcontinue\n\n\t\tfrappe.db.delete(\n\t\t\t\"DocField\",\n\t\t\t{\n\t\t\t\t\"parent\": dt,\n\t\t\t\t\"fieldname\": (\"in\", fields),\n\t\t\t},\n\t\t)\n\n\t\t# Delete the data/column only if delete is specified\n\t\tif not delete:\n\t\t\tcontinue\n\n\t\tif frappe.db.get_value(\"DocType\", dt, \"issingle\"):\n\t\t\tfrappe.db.delete(\n\t\t\t\t\"Singles\",\n\t\t\t\t{\n\t\t\t\t\t\"doctype\": dt,\n\t\t\t\t\t\"field\": (\"in\", fields),\n\t\t\t\t},\n\t\t\t)\n\t\telse:\n\t\t\texisting_fields = frappe.db.describe(dt)\n\t\t\texisting_fields = existing_fields and [e[0] for e in existing_fields] or []\n\t\t\tfields_need_to_delete = set(fields) & set(existing_fields)\n\t\t\tif not fields_need_to_delete:\n\t\t\t\tcontinue\n\n\t\t\tif frappe.db.db_type == \"mariadb\":\n\t\t\t\t# mariadb implicitly commits before DDL, make it explicit\n\t\t\t\tfrappe.db.commit()\n\n\t\t\tquery = \"ALTER TABLE `tab%s` \" % dt + \", \".join(\n\t\t\t\t\"DROP COLUMN `%s`\" % f for f in fields_need_to_delete\n\t\t\t)\n\t\t\tfrappe.db.sql(query)\n\n\t\tif frappe.db.db_type == \"postgres\":\n\t\t\t# commit the results to db\n\t\t\tfrappe.db.commit()\n\n\ndef get_permitted_fields(\n\tdoctype: str, parenttype: str | None = None, user: str | None = None\n) -> list[str]:\n\tmeta = frappe.get_meta(doctype)\n\tvalid_columns = meta.get_valid_columns()\n\n\tif doctype in core_doctypes_list:\n\t\treturn valid_columns\n\n\t# DocType has only fields of type Table (Table, Table MultiSelect)\n\tif set(valid_columns).issubset(default_fields):\n\t\treturn valid_columns\n\n\tif permitted_fields := meta.get_permitted_fieldnames(parenttype=parenttype, user=user):\n\t\tmeta_fields = meta.default_fields.copy()\n\t\toptional_meta_fields = [x for x in optional_fields if x in valid_columns]\n\n\t\tif meta.istable:\n\t\t\tmeta_fields.extend(child_table_fields)\n\n\t\treturn meta_fields + permitted_fields + optional_meta_fields\n\n\treturn []\n", "path": "frappe/model/__init__.py"}]}