Commit cc46d6d4 authored by Romain Courteaud's avatar Romain Courteaud

[erp5_hal_json_style] Speed up listbox column calculation

Shamelessly copy Listbox.py implementation, which limits acquisition usage

For compatibility, do not check local properties when the listbox uses contentValues (ListMethodWrapper).
parent 156b9d4b
from Acquisition import aq_self, aq_base, aq_inner from Acquisition import aq_self, aq_base, aq_inner
from Products.ERP5Type.Utils import UpperCase
from ZODB.POSException import ConflictError
from AccessControl import Unauthorized
from Products.ZSQLCatalog.zsqlbrain import ZSQLBrain
def Base_aqSelf(self): def Base_aqSelf(self):
return aq_self(self) return aq_self(self)
...@@ -17,6 +22,67 @@ def Field_getSubFieldKeyDict(self, field, field_id, key=None): ...@@ -17,6 +22,67 @@ def Field_getSubFieldKeyDict(self, field, field_id, key=None):
"""XXX""" """XXX"""
return field.generate_subfield_key(field_id, key=key) return field.generate_subfield_key(field_id, key=key)
def Listbox_getBrainValue(self, brain, obj, select, can_check_local_property, editable_field=None):
"""
ListBox.py / getValueList
"""
tales = False
# Use a widget, if any.
if editable_field is not None:
# XXX we need to take care of whether the editable field is
# a proxy field or not, because a proxy field may inherit a
# tales expression from a template field, and the API is not
# unified.
get_tales = getattr(editable_field, 'get_recursive_tales',
editable_field.get_tales)
tales = get_tales('default')
if tales:
default_field_value = editable_field.__of__(obj).get_value('default',
cell=brain)
# If a tales expression is not defined, get a skin, an accessor or a property.
if not tales:
if (can_check_local_property) and (getattr(aq_self(brain), select, None) is not None):
default_field_value = getattr(brain, select)
else:
try:
# Get the trailing part.
try:
property_id = select[select.rindex('.') + 1:]
except ValueError:
property_id = select
try:
accessor_name = 'get%s' % UpperCase(property_id)
# Make sure the object have the attribute, and this is not
# acquired, but still get the attribute on the acquisition wrapper
getattr(aq_base(obj), accessor_name)
default_field_value = getattr(obj, accessor_name)
except AttributeError:
default_field_value = getattr(obj, property_id, None)
except (AttributeError, KeyError, Unauthorized):
default_field_value = None
# If the value is callable, evaluate it.
if callable(default_field_value):
try:
try:
default_field_value = default_field_value(brain=brain)
except TypeError:
default_field_value = default_field_value()
except (ConflictError, RuntimeError):
raise
except:
default_field_value = None
# Listbox.py forces result to be an empty string
# This is not needed in hal
# if default_field_value is None:
# default_field_value = ''
return default_field_value
def WorkflowTool_listActionParameterList(self): def WorkflowTool_listActionParameterList(self):
action_list = self.listActions() action_list = self.listActions()
info = self._getOAI(None) info = self._getOAI(None)
......
<?xml version="1.0"?>
<ZopeData>
<record id="1" aka="AAAAAAAAAAE=">
<pickle>
<global name="ExternalMethod" module="Products.ExternalMethod.ExternalMethod"/>
</pickle>
<pickle>
<dictionary>
<item>
<key> <string>_function</string> </key>
<value> <string>Listbox_getBrainValue</string> </value>
</item>
<item>
<key> <string>_module</string> </key>
<value> <string>HalStyle</string> </value>
</item>
<item>
<key> <string>id</string> </key>
<value> <string>Listbox_getBrainValue</string> </value>
</item>
<item>
<key> <string>title</string> </key>
<value> <string></string> </value>
</item>
</dictionary>
</pickle>
</record>
</ZopeData>
...@@ -1835,25 +1835,21 @@ class TestERP5Person_getHateoas_mode_search(ERP5HALJSONStyleSkinsMixin): ...@@ -1835,25 +1835,21 @@ class TestERP5Person_getHateoas_mode_search(ERP5HALJSONStyleSkinsMixin):
@simulate('Base_getRequestUrl', '*args, **kwargs', 'return "http://example.org/bar"') @simulate('Base_getRequestUrl', '*args, **kwargs', 'return "http://example.org/bar"')
@simulate('Base_getRequestHeader', '*args, **kwargs', 'return "application/hal+json"') @simulate('Base_getRequestHeader', '*args, **kwargs', 'return "application/hal+json"')
@simulate('Test_listPersons', '*args, **kwargs', """
return context.getPortalObject().person_module.contentValues(portal_type="Person")
""")
@simulate('Test_listPersonsCatalog', '*args, **kwargs', """
return context.getPortalObject().portal_catalog.searchResults(portal_type="Person")
""")
@changeSkin('Hal') @changeSkin('Hal')
def test_getHateoas_person_title_search(self): def test_getHateoas_contentValues_search(self):
"""Person has amazing property of having attribute "title" and "getTitle" with different return values. """contentValues result must not check local properties
This is a listbox.py compatibility (ListMethodWrapper)
Value resolution must prefer getter over raw attribute.
""" """
fake_request = do_fake_request("GET") fake_request = do_fake_request("GET")
result = self.portal.web_site_module.hateoas.ERP5Document_getHateoas( result = self.portal.web_site_module.hateoas.ERP5Document_getHateoas(
REQUEST=fake_request, REQUEST=fake_request,
mode="search", mode="search",
local_roles=["Assignor", "Assignee"], local_roles=["Owner"],
list_method='Test_listPersons', relative_url='person_module',
list_method='contentValues',
query='uid:"%i"' % self.person.getUid(),
select_list=['title'] # attribute which must be resolved through getter select_list=['title'] # attribute which must be resolved through getter
) )
result_dict = json.loads(result) result_dict = json.loads(result)
...@@ -1866,8 +1862,10 @@ return context.getPortalObject().portal_catalog.searchResults(portal_type="Perso ...@@ -1866,8 +1862,10 @@ return context.getPortalObject().portal_catalog.searchResults(portal_type="Perso
result = self.portal.web_site_module.hateoas.ERP5Document_getHateoas( result = self.portal.web_site_module.hateoas.ERP5Document_getHateoas(
REQUEST=fake_request, REQUEST=fake_request,
mode="search", mode="search",
local_roles=["Assignor", "Assignee"], local_roles=["Owner"],
list_method='Test_listPersonsCatalog', relative_url='person_module',
list_method='searchFolder',
query='uid:"%i"' % self.person.getUid(),
select_list=['title'] # attribute which must be resolved through getter select_list=['title'] # attribute which must be resolved through getter
) )
result_dict = json.loads(result) result_dict = json.loads(result)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment