Переглянути джерело

perf: reduce DB calls made in `get_fetch_values` (#17671) (#17739)

* 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`

(cherry picked from commit f9bfbfec98)

Co-authored-by: Sagar Vora <sagar@resilient.tech>
version-14
mergify[bot] 2 роки тому
committed by GitHub
джерело
коміт
dc19f69929
Не вдалося знайти GPG ключ що відповідає даному підпису Ідентифікатор GPG ключа: 4AEE18F83AFDEB23
2 змінених файлів з 62 додано та 7 видалено
  1. +34
    -7
      frappe/model/utils/__init__.py
  2. +28
    -0
      frappe/tests/test_model_utils.py

+ 34
- 7
frappe/model/utils/__init__.py Переглянути файл

@@ -90,15 +90,42 @@ def get_fetch_values(doctype, fieldname, value):
:param fieldname: Link fieldname selected
:param value: Value selected
"""
out = {}

result = frappe._dict()
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
# 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
- 0
frappe/tests/test_model_utils.py Переглянути файл

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

Завантаження…
Відмінити
Зберегти