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:
Sagar Vora 2022-08-05 06:22:37 +00:00 committed by GitHub
parent 9a50c30586
commit f9bfbfec98
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 63 additions and 8 deletions

View file

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

View 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}
)