wcs: resolve card_ids lazily (#74306) #43
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue