perf: reduce DB calls made in get_fetch_values (#17671)
* perf: reduce DB calls made in `get_fetch_values` * fix: ensure return value is same as before * test: add test for `frappe.model.utils.get_fetch_values`
This commit is contained in:
parent
9a50c30586
commit
f9bfbfec98
2 changed files with 63 additions and 8 deletions
|
|
@ -90,15 +90,42 @@ def get_fetch_values(doctype, fieldname, value):
|
|||
:param fieldname: Link fieldname selected
|
||||
:param value: Value selected
|
||||
"""
|
||||
out = {}
|
||||
meta = frappe.get_meta(doctype)
|
||||
link_df = meta.get_field(fieldname)
|
||||
for df in meta.get_fields_to_fetch(fieldname):
|
||||
# example shipping_address.gistin
|
||||
link_field, source_fieldname = df.fetch_from.split(".", 1)
|
||||
out[df.fieldname] = frappe.db.get_value(link_df.options, value, source_fieldname)
|
||||
|
||||
return out
|
||||
result = frappe._dict()
|
||||
meta = frappe.get_meta(doctype)
|
||||
|
||||
# fieldname in target doctype: fieldname in source doctype
|
||||
fields_to_fetch = {
|
||||
df.fieldname: df.fetch_from.split(".", 1)[1] for df in meta.get_fields_to_fetch(fieldname)
|
||||
}
|
||||
|
||||
# nothing to fetch
|
||||
if not fields_to_fetch:
|
||||
return result
|
||||
|
||||
# initialise empty values for target fields
|
||||
for target_fieldname in fields_to_fetch:
|
||||
result[target_fieldname] = None
|
||||
|
||||
# fetch only if Link field has a truthy value
|
||||
if not value:
|
||||
return result
|
||||
|
||||
db_values = frappe.db.get_value(
|
||||
meta.get_options(fieldname), # source doctype
|
||||
value,
|
||||
tuple(set(fields_to_fetch.values())), # unique source fieldnames
|
||||
as_dict=True,
|
||||
)
|
||||
|
||||
# if value doesn't exist in source doctype, get_value returns None
|
||||
if not db_values:
|
||||
return result
|
||||
|
||||
for target_fieldname, source_fieldname in fields_to_fetch.items():
|
||||
result[target_fieldname] = db_values.get(source_fieldname)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@site_cache(maxsize=128)
|
||||
|
|
|
|||
28
frappe/tests/test_model_utils.py
Normal file
28
frappe/tests/test_model_utils.py
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
import unittest
|
||||
|
||||
import frappe
|
||||
from frappe.model.utils import get_fetch_values
|
||||
|
||||
|
||||
class TestModelUtils(unittest.TestCase):
|
||||
def test_get_fetch_values(self):
|
||||
doctype = "ToDo"
|
||||
|
||||
# no fields to fetch
|
||||
self.assertEqual(get_fetch_values(doctype, "role", "System Manager"), {})
|
||||
|
||||
# no value
|
||||
self.assertEqual(get_fetch_values(doctype, "assigned_by", None), {"assigned_by_full_name": None})
|
||||
|
||||
# no db values
|
||||
self.assertEqual(
|
||||
get_fetch_values(doctype, "assigned_by", "~not-a-user~"), {"assigned_by_full_name": None}
|
||||
)
|
||||
|
||||
# valid db values
|
||||
user = "test@example.com"
|
||||
full_name = frappe.db.get_value("User", user, "full_name")
|
||||
|
||||
self.assertEqual(
|
||||
get_fetch_values(doctype, "assigned_by", user), {"assigned_by_full_name": full_name}
|
||||
)
|
||||
Loading…
Add table
Reference in a new issue