api: do not fully load the related table when filtering on an item(s) field (#74320) #101

Merged
bdauvergne merged 1 commits from wip/74320-Optimiser-la-generation-de-crite into main 2023-02-11 00:47:43 +01:00
4 changed files with 84 additions and 34 deletions

View File

@ -1381,6 +1381,59 @@ def test_api_list_formdata_item_filter(pub, local_user):
assert len(resp.json) == result
def test_api_list_formdata_item_filter_on_cards(pub, local_user, sql_queries):
pub.role_class.wipe()
role = pub.role_class(name='test')
role.store()
local_user.roles = [role.id]
local_user.store()
CardDef.wipe()
carddef = CardDef()
carddef.name = 'test'
carddef.fields = [
fields.StringField(id='0', label='String', type='string', varname='string'),
]
carddef.digest_templates = {'default': '{{ form_var_string }}'}
carddef.store()
card_data_class = carddef.data_class()
card_data_class.wipe()
carddata = card_data_class()
carddata.data = {'0': 'coin'}
carddata.just_created()
carddata.store()
FormDef.wipe()
formdef = FormDef()
formdef.name = 'test'
formdef.workflow_roles = {'_receiver': role.id}
formdef.fields = [
fields.ItemField(
id='0', label='Item', type='item', data_source={'type': 'carddef:test'}, varname='item'
),
]
formdef.store()
data_class = formdef.data_class()
data_class.wipe()
formdata = data_class()
formdata.data = {'0': str(carddata.id)}
formdata.user_id = local_user.id
formdata.just_created()
formdata.jump_status('new')
formdata.store()
sql_queries.clear()
resp = get_app(pub).get(sign_uri('/api/forms/test/list?filter-item=%s' % carddata.id, user=local_user))
assert len(resp.json) == 1
carddata_sql_queries = [q for q in sql_queries if 'FROM carddata' in q]
assert len(carddata_sql_queries) == 1
assert ' id = ' in carddata_sql_queries[0]
def test_api_list_formdata_items_filter(pub, local_user):
pub.role_class.wipe()
role = pub.role_class(name='test')

View File

@ -99,7 +99,7 @@ def sql_queries(monkeypatch):
def cursor(*args, **kwargs):
cur = old_cursor(*args, **kwargs)
mocked_cur = mock.Mock(wraps=cur)
mocked_cur = mock.MagicMock(wraps=cur)
fpeters marked this conversation as resolved Outdated

Qu'est-ce que ça implique ?

Qu'est-ce que ça implique ?

(ok il n'y a pas le commentaire initial dans la vue "fichiers modifiés", c'est répondu).

(ok il n'y a pas le commentaire initial dans la vue "fichiers modifiés", c'est répondu).
old_execute = cur.execute
def execute(*args, **kwargs):

View File

@ -2064,13 +2064,10 @@ class FormPage(FormdefDirectoryBase):
elif filter_field.type in ('item', 'items', 'bool', 'string', 'email', 'date'):
criterias.append(criteria('f%s' % filter_field.id, filter_field_value, field=filter_field))
if filter_field.type in ('item', 'items'):
field_options = filter_field.get_options()
if field_options and type(field_options[0]) in (list, tuple):
for option in field_options:
if filter_field_value in (option[0], option[-1]):
filter_field_value = option[1]
break
criterias[-1]._label = '%s: %s' % (filter_field.label, filter_field_value)
criterias[-1]._label = '%s: %s' % (
filter_field.label,
filter_field.get_display_value(filter_field_value),
)
unknown_filters = sorted(filters_in_request - known_filters)
if unknown_filters:

View File

@ -2183,6 +2183,32 @@ class ItemFieldMixin:
for item in self.items or []:
yield location, None, item
def get_display_value(self, value):
data_source = data_sources.get_object(self.data_source)
if data_source is None:
return get_publisher().translate(value) or ''
if data_source.type == 'jsonp':
if not get_session().jsonp_display_values:
get_session().jsonp_display_values = {}
return get_session().jsonp_display_values.get('%s_%s' % (data_source.get_jsonp_url(), value))
display_value = data_source.get_display_value(value)
session = get_session()
if (
isinstance(session, BasicSession)
and self.display_mode == 'autocomplete'
and data_source
and data_source.can_jsonp()
):
# store display value in session to be used by select2
url = data_source.get_jsonp_url()
if not session.jsonp_display_values:
session.jsonp_display_values = {}
session.jsonp_display_values['%s_%s' % (url, value)] = display_value
return display_value
class ItemField(WidgetField, MapOptionsMixin, ItemFieldMixin):
key = 'item'
@ -2297,32 +2323,6 @@ class ItemField(WidgetField, MapOptionsMixin, ItemFieldMixin):
# SingleSelectHintWidget with custom template
kwargs['template-name'] = 'qommon/forms/widgets/select-timetable.html'
def get_display_value(self, value):
data_source = data_sources.get_object(self.data_source)
if data_source is None:
return get_publisher().translate(value) or ''
if data_source.type == 'jsonp':
if not get_session().jsonp_display_values:
get_session().jsonp_display_values = {}
return get_session().jsonp_display_values.get('%s_%s' % (data_source.get_jsonp_url(), value))
display_value = data_source.get_display_value(value)
session = get_session()
if (
isinstance(session, BasicSession)
and self.display_mode == 'autocomplete'
and data_source
and data_source.can_jsonp()
):
# store display value in session to be used by select2
url = data_source.get_jsonp_url()
if not session.jsonp_display_values:
session.jsonp_display_values = {}
session.jsonp_display_values['%s_%s' % (url, value)] = display_value
return display_value
def get_view_value(self, value, value_id=None, **kwargs):
data_source = data_sources.get_object(self.data_source)
if value and data_source is None: