Merge pull request #31400 from sagarvora/better-table-fieldnames

This commit is contained in:
Sagar Vora 2025-02-25 10:43:29 +05:30 committed by GitHub
commit 99574a74e2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 39 additions and 25 deletions

View file

@ -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.

View file

@ -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

View file

@ -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):