dataviz: evaluate page variables in time range template field (#63181)

This commit is contained in:
Valentin Deniaud 2022-03-30 17:51:41 +02:00
parent 17742635e5
commit 45f67ff368
4 changed files with 66 additions and 22 deletions

View File

@ -209,14 +209,9 @@ class ChartNgForm(ChartFiltersMixin, forms.ModelForm):
continue
context = {'now': datetime.datetime.now, 'today': datetime.datetime.now}
try:
date = Template('{{ %s|date:"Y-m-d" }}' % self.cleaned_data[template_field]).render(
Context(context)
)
Template('{{ %s|date:"Y-m-d" }}' % self.cleaned_data[template_field]).render(Context(context))
except (VariableDoesNotExist, TemplateSyntaxError) as e:
self.add_error(template_field, e)
else:
if not date:
self.add_error(template_field, _('Template does not evaluate to a valid date.'))
class ChartNgPartialForm(ChartFiltersMixin, forms.ModelForm):

View File

@ -30,7 +30,10 @@ class Migration(migrations.Migration):
max_length=200,
validators=[combo.data.models.django_template_validator],
verbose_name='From',
help_text='Template code returning a date. For example, Monday in two weeks would be today|add_days:"14"|adjust_to_week_monday.',
help_text=(
'Template code returning a date. For example, Monday in two weeks would be '
'today|add_days:"14"|adjust_to_week_monday. Page variables are also accessible.'
),
),
),
]

View File

@ -213,7 +213,8 @@ class ChartNgCell(CellBase):
blank=True,
validators=[django_template_validator],
help_text=_(
'Template code returning a date. For example, Monday in two weeks would be today|add_days:"14"|adjust_to_week_monday.'
'Template code returning a date. For example, Monday in two weeks would be '
'today|add_days:"14"|adjust_to_week_monday. Page variables are also accessible.'
),
)
time_range_end_template = models.CharField(
@ -445,21 +446,31 @@ class ChartNgCell(CellBase):
if self.time_range_end:
params['end'] = self.time_range_end
elif self.time_range == 'range-template':
context = {'now': datetime.now, 'today': datetime.now}
if self.time_range_start_template:
params['start'] = Template('{{ %s|date:"Y-m-d" }}' % self.time_range_start_template).render(
Context(context)
)
start = self.evaluate_range_template(self.time_range_start_template)
if start:
params['start'] = start
if self.time_range_end_template:
params['end'] = Template('{{ %s|date:"Y-m-d" }}' % self.time_range_end_template).render(
Context(context)
)
end = self.evaluate_range_template(self.time_range_end_template)
if end:
params['end'] = end
if 'time_interval' in params and not self.statistic.has_native_support_for_interval(
params['time_interval']
):
params['time_interval'] = 'day'
return params
def evaluate_range_template(self, value):
if value in self.page.extra_variables:
value = self.page.extra_variables[value].strip('{ }')
context = self.request_context
context.update({'now': datetime.now, 'today': datetime.now})
try:
return Template('{{ %s|date:"Y-m-d" }}' % value).render(Context(context))
except (VariableDoesNotExist, TemplateSyntaxError):
return None
def evaluate_filter_value(self, value):
if isinstance(value, list) or not value.startswith('variable:'):
return value

View File

@ -1514,8 +1514,9 @@ def test_chartng_cell_manager_new_api_time_range_templates(app, admin_user, new_
assert cell.time_range_end_template == ''
resp.form[field_prefix + 'time_range_start_template'] = 'xxx'
resp = resp.form.submit()
assert 'Template does not evaluate to a valid date.' in resp.text
resp = resp.form.submit().follow()
cell.refresh_from_db()
assert cell.time_range_start_template == 'xxx'
resp = app.get('/manage/pages/%s/' % page.id)
resp.form[field_prefix + 'time_range_start_template'] = 'today|xxx'
@ -1761,8 +1762,16 @@ def test_dataviz_api_list_statistics(new_api_statistics, settings):
@with_httmock(new_api_mock)
@pytest.mark.parametrize('date', ['2020-03-02 12:01', '2020-03-05 12:01']) # Monday and Thursday
def test_chartng_cell_new_api_filter_params(new_api_statistics, nocache, freezer, date):
page = Page.objects.create(title='One', slug='index')
def test_chartng_cell_new_api_filter_params(app, new_api_statistics, nocache, freezer, date):
page = Page.objects.create(
title='One',
slug='index',
extra_variables={
'custom_date': '{{ "2021-02-03"|parse_date }}',
'not-a-date': 'not-a-date',
'syntax-error': '{% for %}',
},
)
cell = ChartNgCell(page=page, order=1, placeholder='content')
cell.statistic = Statistic.objects.get(slug='one-serie')
cell.save()
@ -1826,26 +1835,52 @@ def test_chartng_cell_new_api_filter_params(new_api_statistics, nocache, freezer
request = new_api_mock.call['requests'][-1]
assert 'start=2020-10-01' in request.url and 'end=2020-11-03' in request.url
location = '/api/dataviz/graph/%s/' % cell.pk
cell.time_range = 'range-template'
cell.save()
cell.get_chart()
app.get(location)
request = new_api_mock.call['requests'][-1]
assert 'start' not in urllib.parse.parse_qs(urllib.parse.urlparse(request.url).query)
assert 'end' not in urllib.parse.parse_qs(urllib.parse.urlparse(request.url).query)
cell.time_range_start_template = 'today|add_days:"7"|adjust_to_week_monday'
cell.save()
cell.get_chart()
app.get(location)
request = new_api_mock.call['requests'][-1]
assert 'start=2020-03-09' in request.url
assert 'end' not in urllib.parse.parse_qs(urllib.parse.urlparse(request.url).query)
cell.time_range_end_template = 'today|add_days:"14"|adjust_to_week_monday'
cell.save()
cell.get_chart()
app.get(location)
request = new_api_mock.call['requests'][-1]
assert 'start=2020-03-09' in request.url and 'end=2020-03-16' in request.url
cell.time_range_start_template = 'xxx'
cell.save()
app.get(location)
request = new_api_mock.call['requests'][-1]
assert 'start' not in request.url
# use page variables
cell.time_range_start_template = 'custom_date'
cell.save()
app.get(location)
request = new_api_mock.call['requests'][-1]
assert 'start=2021-02-03' in request.url
cell.time_range_start_template = 'not-a-date'
cell.save()
app.get(location)
request = new_api_mock.call['requests'][-1]
assert 'start' not in request.url
cell.time_range_start_template = 'syntax-error'
cell.save()
app.get(location)
request = new_api_mock.call['requests'][-1]
assert 'start' not in request.url
@with_httmock(new_api_mock)
def test_chartng_cell_new_api_filter_params_month(new_api_statistics, nocache, freezer):