wcs: resolve card_ids lazily (#74306) #43

Merged
fpeters merged 2 commits from wip/74306-wcs-resoudre-la-liste-des-ids-de into main 2023-02-10 09:13:29 +01:00
2 changed files with 70 additions and 17 deletions

View File

@ -822,6 +822,19 @@ class CardMixin:
return escape(self.custom_title) or self.cached_title or None
class LazyValue:
sentinel = object()
def __init__(self, getter):
self.value = self.sentinel
self.getter = getter
def __call__(self):
if self.value is self.sentinel:
self.value = self.getter()
return self.value
@register_cell_class
class WcsCardCell(CardMixin, CellBase):
carddef_reference = models.CharField(_('Card Model'), max_length=150)
@ -872,6 +885,12 @@ class WcsCardCell(CardMixin, CellBase):
class Meta:
verbose_name = _('Card(s)')
def get_card_ids(self, context):
lazy_value = context.get(self.global_context_key)
if lazy_value is not None:
return lazy_value()
return []
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
@ -960,14 +979,14 @@ class WcsCardCell(CardMixin, CellBase):
# don't call wcs on page loading
return
if self.carddef_reference and self.global_context_key not in context:
card_ids = self.get_card_ids(context, request)
context[self.global_context_key] = card_ids
# self.resolve_card_ids(context, request)
context[self.global_context_key] = LazyValue(lambda: self.resolve_card_ids(context, request))
def get_repeat_template(self, context):
if self.display_mode == 'table':
# don't repeat cell if table display mode
return []
return len(context.get(self.global_context_key) or [])
return len(self.get_card_ids(context))
def get_related_card_path(self):
if self.related_card_path == '__all__':
@ -1026,7 +1045,7 @@ class WcsCardCell(CardMixin, CellBase):
def get_card_data_from_ids(self, card_id, context):
# get the correct card from all known cards for ids in context
card_ids = context.get(self.global_context_key)
card_ids = self.get_card_ids(context)
if not card_ids:
return None
if len(card_ids) == 1:
@ -1324,7 +1343,7 @@ class WcsCardCell(CardMixin, CellBase):
except (VariableDoesNotExist, TemplateSyntaxError):
return []
def get_card_ids(self, original_context, request):
def resolve_card_ids(self, original_context, request):
if not self.carddef_reference:
# not configured
return []
@ -1367,10 +1386,10 @@ class WcsCardCell(CardMixin, CellBase):
return []
def get_card_id(self, context):
repeat_index = getattr(self, 'repeat_index', context.get('repeat_index'))
repeat_index = getattr(self, 'repeat_index', context.get('repeat_index')) or 0
if repeat_index is not None:
try:
return context.get(self.global_context_key)[repeat_index]
return self.get_card_ids(context)[repeat_index]
except (IndexError, TypeError):
return None
@ -1475,7 +1494,7 @@ class WcsCardCell(CardMixin, CellBase):
card_page = matching_pages[0]
extra_context['card_page_base_url'] = card_page.get_online_url()
card_ids = context.get(self.global_context_key)
card_ids = self.get_card_ids(context)
if not card_ids and self.related_card_path != '__all__':
extra_context['card_objects'] = []
else:

View File

@ -1360,7 +1360,7 @@ def test_card_cell_table_mode_render_identifier(mock_send, nocache, app):
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_table_mode_render_identifier_from_related(mock_send, nocache, app):
def test_card_cell_table_mode_render_identifier_from_related(mock_send, app):
page = Page.objects.create(title='xxx', slug='foo', template_name='standard')
WcsCardCell.objects.create(
page=page,
@ -1407,6 +1407,8 @@ def test_card_cell_table_mode_render_identifier_from_related(mock_send, nocache,
check(urls)
# direct and multiple relation (items)
# clear cache to see call to /api/cards/card_a/1/
cache.clear()
cell2.carddef_reference = 'default:card_b' # reset
cell2.related_card_path = 'sluga/cardsb'
cell2.save()
@ -1419,6 +1421,43 @@ def test_card_cell_table_mode_render_identifier_from_related(mock_send, nocache,
check(urls)
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_table_mode_lazy_card_ids(mock_send, nocache, app):
'''Check if templated card_ids are resolved for other non related cells on
the same page, like a templated text cell.'''
page = Page.objects.create(title='xxx', slug='foo', template_name='standard')
WcsCardCell.objects.create(
page=page,
placeholder='content',
order=0,
display_mode='table',
slug='sluga',
carddef_reference='default:card_a',
card_ids='{{ cards|objects:"card_model_1"|getlist:"id"|join:"," }}',
related_card_path='',
)
TextCell.objects.create(
page=page,
placeholder='content',
order=1,
slug='slugb',
text='{{ cards|objects:"card_model_x"|getlist:"id"|join:"," }}',
)
resp = app.get(page.get_online_url())
cell_divs = resp.pyquery('div.cell')
assert len(cell_divs) == 2
send_counts = {}
for cell_div in cell_divs.items():
mock_send.reset_mock()
cell_url = cell_div.attr['data-ajax-cell-url']
extra_context = cell_div.attr['data-extra-context']
app.get(cell_url + '?ctx=' + extra_context)
send_counts[cell_div.attr['id']] = len(mock_send.call_args_list)
# rendering of "slugb" text cell should not make any request.
assert send_counts == {'sluga': 2, 'slugb': 0}
@mock.patch('requests.Session.send', side_effect=mocked_requests_send)
def test_card_cell_table_mode_render_title(mock_send, context):
page = Page.objects.create(title='xxx', template_name='standard')
@ -2275,10 +2314,10 @@ def test_card_cell_card_mode_render_custom_schema_link_entry(mock_send, context,
assert PyQuery(result).find('.value a').attr['class'] is None
# empty label or no value/no file field/unknown field: no link in output
context[cell.global_context_key] = [12]
context[cell.global_context_key] = lambda: [12]
result = cell.render(context)
assert PyQuery(result).find('.value a') == []
context[cell.global_context_key] = [11]
context[cell.global_context_key] = lambda: [11]
cell.modify_global_context(context, request)
cell.repeat_index = 0
cell.custom_schema['cells'][0]['link_field'] = 'fielda'
@ -2559,12 +2598,7 @@ def test_card_cell_card_mode_render_identifier_from_related(mock_send, nocache,
# multiple ids configured on first cell
cell.card_ids = '{{ cards|objects:"card_a"|getlist:"id"|join:"," }}'
cell.save()
failing(
urls=[
# get first cell data
'/api/cards/card_a/list',
]
)
failing(urls=[])
# related_card_path configured on first cell
cell.card_ids = '1' # reset