Merge pull request #31400 from sagarvora/better-table-fieldnames
This commit is contained in:
commit
99574a74e2
3 changed files with 39 additions and 25 deletions
|
|
@ -53,9 +53,13 @@ DOCTYPE_TABLE_FIELDS = [
|
|||
]
|
||||
|
||||
TABLE_DOCTYPES_FOR_DOCTYPE = {df["fieldname"]: df["options"] for df in DOCTYPE_TABLE_FIELDS}
|
||||
|
||||
# child tables cannot have child tables
|
||||
TABLE_DOCTYPES_FOR_DOCTYPE_TABLES = {}
|
||||
|
||||
DOCTYPES_FOR_DOCTYPE = {"DocType", *TABLE_DOCTYPES_FOR_DOCTYPE.values()}
|
||||
|
||||
UNPICKLABLE_KEYS = ("meta", "permitted_fieldnames", "_parent_doc", "_weakref")
|
||||
UNPICKLABLE_KEYS = ("meta", "permitted_fieldnames", "_parent_doc", "_weakref", "_table_fieldnames")
|
||||
|
||||
|
||||
def get_controller(doctype):
|
||||
|
|
@ -139,7 +143,6 @@ class BaseDocument:
|
|||
if d.get("doctype"):
|
||||
self.doctype = d["doctype"]
|
||||
|
||||
self._table_fieldnames = {df.fieldname for df in self._get_table_fields()}
|
||||
self.update(d)
|
||||
self.dont_update_if_missing = []
|
||||
|
||||
|
|
@ -355,6 +358,16 @@ class BaseDocument:
|
|||
|
||||
return value
|
||||
|
||||
@cached_property
|
||||
def _table_fieldnames(self) -> dict:
|
||||
if self.doctype == "DocType":
|
||||
return TABLE_DOCTYPES_FOR_DOCTYPE
|
||||
|
||||
if self.doctype in DOCTYPES_FOR_DOCTYPE:
|
||||
return TABLE_DOCTYPES_FOR_DOCTYPE_TABLES
|
||||
|
||||
return self.meta._table_doctypes
|
||||
|
||||
def _get_table_fields(self):
|
||||
"""
|
||||
To get table fields during Document init
|
||||
|
|
@ -556,17 +569,17 @@ class BaseDocument:
|
|||
return frappe.as_json(self.as_dict())
|
||||
|
||||
def get_table_field_doctype(self, fieldname):
|
||||
try:
|
||||
return self.meta.get_field(fieldname).options
|
||||
except AttributeError:
|
||||
if self.doctype == "DocType" and (table_doctype := TABLE_DOCTYPES_FOR_DOCTYPE.get(fieldname)):
|
||||
return table_doctype
|
||||
|
||||
raise
|
||||
return self._table_fieldnames.get(fieldname)
|
||||
|
||||
def get_parentfield_of_doctype(self, doctype):
|
||||
fieldname = [df.fieldname for df in self.meta.get_table_fields() if df.options == doctype]
|
||||
return fieldname[0] if fieldname else None
|
||||
return next(
|
||||
(
|
||||
fieldname
|
||||
for fieldname, child_doctype in self._table_fieldnames.items()
|
||||
if child_doctype == doctype
|
||||
),
|
||||
None,
|
||||
)
|
||||
|
||||
def db_insert(self, ignore_if_duplicate=False):
|
||||
"""INSERT the document (with valid columns) in the database.
|
||||
|
|
|
|||
|
|
@ -270,20 +270,20 @@ class Document(BaseDocument, DocRef):
|
|||
return self
|
||||
|
||||
def load_children_from_db(self):
|
||||
for df in self._get_table_fields():
|
||||
for fieldname, child_doctype in self._table_fieldnames.items():
|
||||
# Make sure not to query the DB for a child table, if it is a virtual one.
|
||||
# During frappe is installed, the property "is_virtual" is not available in tabDocType, so
|
||||
# we need to filter those cases for the access to frappe.db.get_value() as it would crash otherwise.
|
||||
if hasattr(self, "doctype") and not hasattr(self, "module") and is_virtual_doctype(df.options):
|
||||
self.set(df.fieldname, [])
|
||||
if hasattr(self, "doctype") and not hasattr(self, "module") and is_virtual_doctype(child_doctype):
|
||||
self.set(fieldname, [])
|
||||
continue
|
||||
|
||||
if self.doctype == "DocType":
|
||||
# This special handling is required because of bootstrapping code that doesn't
|
||||
# handle failures correctly.
|
||||
children = frappe.db.get_values(
|
||||
df.options,
|
||||
{"parent": self.name, "parenttype": self.doctype, "parentfield": df.fieldname},
|
||||
child_doctype,
|
||||
{"parent": self.name, "parenttype": self.doctype, "parentfield": fieldname},
|
||||
"*",
|
||||
as_dict=True,
|
||||
order_by="idx asc",
|
||||
|
|
@ -297,14 +297,14 @@ class Document(BaseDocument, DocRef):
|
|||
AND `parenttype`= %(parenttype)s
|
||||
AND `parentfield`= %(parentfield)s
|
||||
ORDER BY `idx` ASC {for_update}""".format(
|
||||
table_name=get_table_name(df.options, wrap_in_backticks=True),
|
||||
table_name=get_table_name(child_doctype, wrap_in_backticks=True),
|
||||
for_update="FOR UPDATE" if self.flags.for_update else "",
|
||||
),
|
||||
{"parent": self.name, "parenttype": self.doctype, "parentfield": df.fieldname},
|
||||
{"parent": self.name, "parenttype": self.doctype, "parentfield": fieldname},
|
||||
as_dict=True,
|
||||
)
|
||||
|
||||
self.set(df.fieldname, children or [])
|
||||
self.set(fieldname, children or [])
|
||||
|
||||
return self
|
||||
|
||||
|
|
@ -568,6 +568,7 @@ class Document(BaseDocument, DocRef):
|
|||
if getattr(self.meta, "is_virtual", False):
|
||||
# Virtual doctypes manage their own children
|
||||
return
|
||||
|
||||
for df in self.meta.get_table_fields():
|
||||
self.update_child_table(df.fieldname, df)
|
||||
|
||||
|
|
@ -1097,11 +1098,11 @@ class Document(BaseDocument, DocRef):
|
|||
|
||||
children = []
|
||||
|
||||
for df in self.meta.get_table_fields():
|
||||
if parenttype and df.options != parenttype:
|
||||
for fieldname, child_doctype in self._table_fieldnames.items():
|
||||
if parenttype and child_doctype != parenttype:
|
||||
continue
|
||||
|
||||
if value := self.get(df.fieldname):
|
||||
if value := self.get(fieldname):
|
||||
children.extend(value)
|
||||
|
||||
return children
|
||||
|
|
|
|||
|
|
@ -307,9 +307,6 @@ class Meta(Document):
|
|||
|
||||
return valid_fields
|
||||
|
||||
def get_table_field_doctype(self, fieldname):
|
||||
return TABLE_DOCTYPES_FOR_DOCTYPE.get(fieldname)
|
||||
|
||||
def get_field(self, fieldname):
|
||||
"""Return docfield from meta."""
|
||||
|
||||
|
|
@ -535,6 +532,9 @@ class Meta(Document):
|
|||
else:
|
||||
self._table_fields = self.get("fields", {"fieldtype": ["in", table_fields]})
|
||||
|
||||
# table fieldname: doctype map
|
||||
self._table_doctypes = {field.fieldname: field.options for field in self._table_fields}
|
||||
|
||||
def sort_fields(self):
|
||||
"""
|
||||
Sort fields on the basis of following rules (priority descending):
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue