Project

General

Profile

0001-dataviz-add-time-range-fields-49248.patch

Valentin Deniaud, 15 December 2020 05:32 PM

Download (10.5 KB)

View differences:

Subject: [PATCH] dataviz: add time range fields (#49248)

 combo/apps/dataviz/forms.py                   | 11 ++++-
 .../migrations/0016_auto_20201215_1624.py     | 30 +++++++++++++
 combo/apps/dataviz/models.py                  | 44 ++++++++++++++++++-
 .../templates/combo/chartngcell_form.html     | 16 +++++++
 tests/test_dataviz.py                         | 36 ++++++++++++++-
 5 files changed, 132 insertions(+), 5 deletions(-)
 create mode 100644 combo/apps/dataviz/migrations/0016_auto_20201215_1624.py
combo/apps/dataviz/forms.py
48 48

  
49 49
    class Meta:
50 50
        model = ChartNgCell
51
        fields = ('title', 'statistic', 'chart_type', 'height', 'sort_order',
52
                  'hide_null_values')
51
        fields = ('title', 'statistic', 'time_range','time_range_start', 'time_range_end',  'chart_type',
52
                  'height', 'sort_order', 'hide_null_values')
53
        widgets = {
54
            'time_range_start': forms.DateInput(attrs={'type': 'date'}, format='%Y-%m-%d'),
55
            'time_range_end': forms.DateInput(attrs={'type': 'date'}, format='%Y-%m-%d'),
56
        }
53 57

  
54 58
    def __init__(self, *args, **kwargs):
55 59
        super().__init__(*args, **kwargs)
......
80 84
        # reorder so that filter fields appear after 'statistic' field
81 85
        self.fields = OrderedDict((field_id, self.fields[field_id]) for field_id in field_ids)
82 86

  
87
        if self.instance.statistic.service_slug == 'bijoe':
88
            self.fields.pop('time_range')
89

  
83 90
    def save(self, *args, **kwargs):
84 91
        if 'statistic' in self.changed_data:
85 92
            self.instance.filter_params.clear()
combo/apps/dataviz/migrations/0016_auto_20201215_1624.py
1
# -*- coding: utf-8 -*-
2
# Generated by Django 1.11.29 on 2020-12-15 15:24
3
from __future__ import unicode_literals
4

  
5
from django.db import migrations, models
6

  
7

  
8
class Migration(migrations.Migration):
9

  
10
    dependencies = [
11
        ('dataviz', '0015_auto_20201202_1424'),
12
    ]
13

  
14
    operations = [
15
        migrations.AddField(
16
            model_name='chartngcell',
17
            name='time_range',
18
            field=models.CharField(blank=True, choices=[('current-year', 'Current year'), ('previous-year', 'Previous year'), ('current-month', 'Current month'), ('previous-month', 'Previous month'), ('range', 'Free range')], max_length=20, verbose_name='Filtering (time)'),
19
        ),
20
        migrations.AddField(
21
            model_name='chartngcell',
22
            name='time_range_end',
23
            field=models.DateField(blank=True, null=True, verbose_name='To'),
24
        ),
25
        migrations.AddField(
26
            model_name='chartngcell',
27
            name='time_range_start',
28
            field=models.DateField(blank=True, null=True, verbose_name='From'),
29
        ),
30
    ]
combo/apps/dataviz/models.py
16 16

  
17 17
import copy
18 18
import os
19
from datetime import date
19 20

  
20 21
from django.urls import reverse
21 22
from django.db import models
23
from django.utils import timezone
22 24
from django.utils.encoding import force_text
23 25
from django.utils.translation import ugettext_lazy as _, ungettext, gettext
24 26
from django.conf import settings
......
137 139

  
138 140
@register_cell_class
139 141
class ChartNgCell(CellBase):
142
    TIME_FILTERS = (
143
        ('current-year', _('Current year')),
144
        ('previous-year', _('Previous year')),
145
        ('current-month', _('Current month')),
146
        ('previous-month', _('Previous month')),
147
        ('range', _('Free range')),
148
    )
149

  
140 150
    statistic = models.ForeignKey(
141 151
        verbose_name=_('Data'), to=Statistic, blank=False, null=True, on_delete=models.SET_NULL, related_name='cells'
142 152
    )
143 153
    filter_params = JSONField(default=dict)
144 154
    title = models.CharField(_('Title'), max_length=150, blank=True)
155
    time_range = models.CharField(
156
        _('Filtering (time)'),
157
        max_length=20,
158
        blank=True,
159
        choices=(
160
            ('current-year', _('Current year')),
161
            ('previous-year', _('Previous year')),
162
            ('current-month', _('Current month')),
163
            ('previous-month', _('Previous month')),
164
            ('range', _('Free range')),
165
        )
166
    )
167
    time_range_start = models.DateField(_('From'), null=True, blank=True)
168
    time_range_end = models.DateField(_('To'), null=True, blank=True)
145 169
    chart_type = models.CharField(_('Chart Type'), max_length=20, default='bar',
146 170
            choices=(
147 171
                ('bar', _('Bar')),
......
215 239
    def get_chart(self, width=None, height=None, raise_if_not_cached=False):
216 240
        response = requests.get(
217 241
                self.statistic.url,
218
                params=self.filter_params,
242
                params=self.get_filter_params(),
219 243
                cache_duration=300,
220 244
                remote_service='auto',
221 245
                without_user=True,
......
267 291

  
268 292
        return chart
269 293

  
294
    def get_filter_params(self):
295
        params = self.filter_params.copy()
296
        now = timezone.now().date()
297
        if self.time_range == 'current-year':
298
            params['start'] = date(year=now.year, month=1, day=1)
299
        elif self.time_range == 'previous-year':
300
            params['start'] = date(year=now.year - 1, month=1, day=1)
301
            params['end'] = date(year=now.year, month=1, day=1)
302
        elif self.time_range == 'current-month':
303
            params['start'] = date(year=now.year, month=now.month, day=1)
304
        elif self.time_range == 'previous-month':
305
            params['start'] = date(year=now.year, month=now.month - 1, day=1)
306
            params['end'] = date(year=now.year, month=now.month, day=1)
307
        elif self.time_range == 'range':
308
            params['start'] = self.time_range_start
309
            params['end'] = self.time_range_end
310
        return params
311

  
270 312
    def parse_response(self, response, chart):
271 313
        # normalize axis to have a fake axis when there are no dimensions and
272 314
        # always a x axis when there is a single dimension.
combo/apps/dataviz/templates/combo/chartngcell_form.html
6 6
</div>
7 7
{% endif %}
8 8
</div>
9

  
10
<script>
11
	$(function () {
12
		start_field = $('#id_cdataviz_chartngcell-{{ cell.pk }}-time_range_start');
13
		end_field = $('#id_cdataviz_chartngcell-{{ cell.pk }}-time_range_end');
14
		$('#id_cdataviz_chartngcell-{{ cell.pk }}-time_range').change(function() {
15
			if(this.value == 'range') {
16
				start_field.parent().show();
17
				end_field.parent().show();
18
			} else {
19
				start_field.parent().hide();
20
				end_field.parent().hide();
21
			}
22
		}).change();
23
	});
24
</script>
tests/test_dataviz.py
2 2

  
3 3
import mock
4 4
import pytest
5
from datetime import timedelta
5
from datetime import timedelta, date
6 6
from httmock import HTTMock, with_httmock, remember_called, urlmatch
7 7
from requests.exceptions import HTTPError
8 8

  
......
909 909
    assert statistics_field.value == str(cell.statistic.pk)
910 910
    assert statistics_field.options[1][2] == 'test: eighth visualization (duration)'
911 911
    assert not 'Unavailable Stat' in resp.text
912
    assert 'time_range' not in resp.form.fields
912 913

  
913 914
    cell.statistic = Statistic.objects.get(slug='unavailable-stat')
914 915
    cell.save()
......
963 964
    cell.refresh_from_db()
964 965
    assert cell.filter_params == {'time_interval': 'month'}
965 966

  
967
    resp.form[field_prefix + 'time_range'] = 'previous-year'
968
    resp = resp.form.submit().follow()
969
    cell.refresh_from_db()
970
    assert cell.time_range == 'previous-year'
971

  
972
    resp.form[field_prefix + 'time_range'] = 'range'
973
    resp.form[field_prefix + 'time_range_start'] = '2020-10-01'
974
    resp.form[field_prefix + 'time_range_end'] = '2020-11-03'
975
    resp = resp.form.submit().follow()
976
    cell.refresh_from_db()
977
    assert cell.time_range == 'range'
978
    assert cell.time_range_start == date(year=2020, month=10, day=1)
979
    assert cell.time_range_end == date(year=2020, month=11, day=3)
980

  
966 981
    no_filters_stat = Statistic.objects.get(slug='two-series')
967 982
    resp.form[field_prefix + 'statistic'] = no_filters_stat.pk
968 983
    resp = resp.form.submit().follow()
......
1175 1190

  
1176 1191

  
1177 1192
@with_httmock(new_api_mock)
1178
def test_chartng_cell_new_api_filter_params(new_api_statistics, nocache):
1193
def test_chartng_cell_new_api_filter_params(new_api_statistics, nocache, freezer):
1179 1194
    page = Page.objects.create(title='One', slug='index')
1180 1195
    cell = ChartNgCell(page=page, order=1, placeholder='content')
1181 1196
    cell.statistic = Statistic.objects.get(slug='one-serie')
......
1192 1207
    request = new_api_mock.call['requests'][1]
1193 1208
    assert 'time_interval=day' in request.url
1194 1209
    assert 'ou=default' in request.url
1210

  
1211
    freezer.move_to('2020-03-02 12:01')
1212
    cell.time_range = 'previous-year'
1213
    cell.save()
1214
    chart = cell.get_chart()
1215
    request = new_api_mock.call['requests'][2]
1216
    assert 'time_interval=day' in request.url
1217
    assert 'ou=default' in request.url
1218
    assert 'start=2019-01-01' in request.url and '2020-01-01' in request.url
1219

  
1220
    cell.time_range = 'range'
1221
    cell.time_range_start = '2020-10-01'
1222
    cell.time_range_end = '2020-11-03'
1223
    cell.save()
1224
    chart = cell.get_chart()
1225
    request = new_api_mock.call['requests'][3]
1226
    assert 'start=2020-10-01' in request.url and '2020-11-03' in request.url
1195
-