0003-dataviz-change-time-interval-aggregation-internals-6.patch
combo/apps/dataviz/forms.py | ||
---|---|---|
57 | 57 |
class ChartNgForm(forms.ModelForm): |
58 | 58 |
blank_choice = ('', '---------') |
59 | 59 |
time_intervals = ( |
60 |
('_week', _('Week')),
|
|
61 |
('_month', _('Month')),
|
|
62 |
('_year', _('Year')),
|
|
63 |
('_weekday', _('Week day')),
|
|
60 |
('week', _('Week')), |
|
61 |
('month', _('Month')), |
|
62 |
('year', _('Year')), |
|
63 |
('weekday', _('Week day')), |
|
64 | 64 |
) |
65 | 65 | |
66 | 66 |
class Meta: |
... | ... | |
146 | 146 |
if 'day' not in choice_ids: |
147 | 147 |
return |
148 | 148 |
for choice in self.time_intervals: |
149 |
if choice[0].strip('_') not in choice_ids:
|
|
149 |
if choice[0] not in choice_ids: |
|
150 | 150 |
self.fields['time_interval'].choices.append(choice) |
151 | 151 | |
152 | 152 |
def clean(self): |
combo/apps/dataviz/migrations/0020_auto_20220118_1103.py | ||
---|---|---|
1 |
# Generated by Django 2.2.19 on 2022-01-18 10:03 |
|
2 | ||
3 |
from django.db import migrations |
|
4 | ||
5 | ||
6 |
def update_time_intervals(apps, schema_editor): |
|
7 |
ChartNgCell = apps.get_model('dataviz', 'ChartNgCell') |
|
8 | ||
9 |
for cell in ChartNgCell.objects.all(): |
|
10 |
save = False |
|
11 |
for param in cell.filter_params: |
|
12 |
if param == 'time_interval' and cell.filter_params[param].startswith('_'): |
|
13 |
cell.filter_params[param] = cell.filter_params[param][1:] |
|
14 |
save = True |
|
15 |
if save: |
|
16 |
cell.save() |
|
17 | ||
18 | ||
19 |
class Migration(migrations.Migration): |
|
20 | ||
21 |
dependencies = [ |
|
22 |
('dataviz', '0019_auto_20211006_1525'), |
|
23 |
] |
|
24 | ||
25 |
operations = [ |
|
26 |
migrations.RunPython(update_time_intervals, migrations.RunPython.noop), |
|
27 |
] |
combo/apps/dataviz/models.py | ||
---|---|---|
148 | 148 |
def natural_key(self): |
149 | 149 |
return (self.slug, self.site_slug, self.service_slug) |
150 | 150 | |
151 |
def has_native_support_for_interval(self, time_interval): |
|
152 |
# pylint: disable=not-an-iterable |
|
153 |
return any( |
|
154 |
time_interval == x['id'] |
|
155 |
for filter_ in self.filters |
|
156 |
for x in filter_['options'] |
|
157 |
if filter_['id'] == 'time_interval' |
|
158 |
) |
|
159 | ||
151 | 160 | |
152 | 161 |
TIME_FILTERS = ( |
153 | 162 |
('previous-year', _('Previous year')), |
... | ... | |
350 | 359 |
data = response['data'] |
351 | 360 | |
352 | 361 |
interval = self.filter_params.get('time_interval', '') |
353 |
if data['x_labels'] and (interval == 'day' or interval.startswith('_')): |
|
362 |
if ( |
|
363 |
data['x_labels'] |
|
364 |
and interval |
|
365 |
and (interval == 'day' or not self.statistic.has_native_support_for_interval(interval)) |
|
366 |
): |
|
354 | 367 |
self.aggregate_data(data, interval) |
355 | 368 | |
356 | 369 |
chart.x_labels = data['x_labels'] |
... | ... | |
421 | 434 |
params['end'] = Template('{{ %s|date:"Y-m-d" }}' % self.time_range_end_template).render( |
422 | 435 |
Context(context) |
423 | 436 |
) |
424 |
if 'time_interval' in params and params['time_interval'].startswith('_'): |
|
437 |
if 'time_interval' in params and not self.statistic.has_native_support_for_interval( |
|
438 |
params['time_interval'] |
|
439 |
): |
|
425 | 440 |
params['time_interval'] = 'day' |
426 | 441 |
return params |
427 | 442 | |
... | ... | |
625 | 640 |
# "W" and "o" are interpreted by Django's date filter and should be left as is. First W is |
626 | 641 |
# backslash escaped to prevent it from being interpreted, translators should refer to Django's |
627 | 642 |
# documentation in order to know if the new letter resulting of translation should be escaped or not. |
628 |
'_week': gettext(r'\WW-o'),
|
|
629 |
'_month': 'm-Y',
|
|
630 |
'_year': 'Y',
|
|
631 |
'_weekday': 'l',
|
|
643 |
'week': gettext(r'\WW-o'), |
|
644 |
'month': 'm-Y', |
|
645 |
'year': 'Y', |
|
646 |
'weekday': 'l', |
|
632 | 647 |
} |
633 | 648 |
if interval == 'day': |
634 | 649 |
x_labels = [ |
635 | 650 |
format_date(min_date + timedelta(days=i), date_formats['day']) |
636 | 651 |
for i in range((max_date - min_date).days + 1) |
637 | 652 |
] |
638 |
elif interval == '_month':
|
|
653 |
elif interval == 'month': |
|
639 | 654 |
month_difference = max_date.month - min_date.month + (max_date.year - min_date.year) * 12 |
640 | 655 |
x_labels = [ |
641 |
format_date(min_date + relativedelta(months=i), date_formats['_month'])
|
|
656 |
format_date(min_date + relativedelta(months=i), date_formats['month']) |
|
642 | 657 |
for i in range(month_difference + 1) |
643 | 658 |
] |
644 |
elif interval == '_year':
|
|
659 |
elif interval == 'year': |
|
645 | 660 |
x_labels = [str(year) for year in range(min_date.year, max_date.year + 1)] |
646 |
elif interval == '_weekday':
|
|
661 |
elif interval == 'weekday': |
|
647 | 662 |
x_labels = [str(label) for label in WEEKDAYS.values()] |
648 |
elif interval == '_week':
|
|
663 |
elif interval == 'week': |
|
649 | 664 |
x_labels = [] |
650 | 665 |
date, last_date = min_date, max_date |
651 | 666 |
if min_date.weekday() > max_date.weekday(): |
652 | 667 |
last_date += relativedelta(weeks=1) |
653 | 668 |
while date <= last_date: |
654 |
x_labels.append(format_date(date, date_formats['_week']))
|
|
669 |
x_labels.append(format_date(date, date_formats['week'])) |
|
655 | 670 |
date += relativedelta(weeks=1) |
656 | 671 | |
657 | 672 |
aggregates = OrderedDict((label, [0] * len(series_data)) for label in x_labels) |
tests/test_dataviz.py | ||
---|---|---|
1211 | 1211 |
('day', False, 'Day'), |
1212 | 1212 |
('month', True, 'Month'), |
1213 | 1213 |
('year', False, 'Year'), |
1214 |
('_week', False, 'Week'),
|
|
1215 |
('_weekday', False, 'Week day'),
|
|
1214 |
('week', False, 'Week'), |
|
1215 |
('weekday', False, 'Week day'), |
|
1216 | 1216 |
] |
1217 | 1217 | |
1218 | 1218 |
ou_field = resp.form[field_prefix + 'ou'] |
... | ... | |
1667 | 1667 |
assert time_interval_field.value == 'day' |
1668 | 1668 |
assert time_interval_field.options == [ |
1669 | 1669 |
('day', True, 'Day'), |
1670 |
('_week', False, 'Week'),
|
|
1671 |
('_month', False, 'Month'),
|
|
1672 |
('_year', False, 'Year'),
|
|
1673 |
('_weekday', False, 'Week day'),
|
|
1670 |
('week', False, 'Week'), |
|
1671 |
('month', False, 'Month'), |
|
1672 |
('year', False, 'Year'), |
|
1673 |
('weekday', False, 'Week day'), |
|
1674 | 1674 |
] |
1675 | 1675 |
resp.form.submit() |
1676 | 1676 |
cell.refresh_from_db() |
... | ... | |
1682 | 1682 |
assert chart.raw_series[0][0][:8] == [0, 0, 0, 0, 0, 0, 0, 1] |
1683 | 1683 |
assert chart.raw_series[1][0][:8] == [2, 0, 0, 0, 0, 0, 0, 2] |
1684 | 1684 | |
1685 |
time_interval_field.value = '_month'
|
|
1685 |
time_interval_field.value = 'month' |
|
1686 | 1686 |
resp.form.submit() |
1687 | 1687 |
cell.refresh_from_db() |
1688 | 1688 | |
... | ... | |
1696 | 1696 |
([4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], {'title': 'Serie 2'}), |
1697 | 1697 |
] |
1698 | 1698 | |
1699 |
time_interval_field.value = '_year'
|
|
1699 |
time_interval_field.value = 'year' |
|
1700 | 1700 |
resp.form.submit() |
1701 | 1701 |
cell.refresh_from_db() |
1702 | 1702 | |
... | ... | |
1708 | 1708 |
([5, 0, 0], {'title': 'Serie 2'}), |
1709 | 1709 |
] |
1710 | 1710 | |
1711 |
time_interval_field.value = '_weekday'
|
|
1711 |
time_interval_field.value = 'weekday' |
|
1712 | 1712 |
resp.form.submit() |
1713 | 1713 |
cell.refresh_from_db() |
1714 | 1714 | |
... | ... | |
1720 | 1720 |
([1, 4, 0, 0, 0, 0, 0], {'title': 'Serie 2'}), |
1721 | 1721 |
] |
1722 | 1722 | |
1723 |
time_interval_field.value = '_week'
|
|
1723 |
time_interval_field.value = 'week' |
|
1724 | 1724 |
resp.form.submit() |
1725 | 1725 |
cell.refresh_from_db() |
1726 | 1726 | |
1727 |
- |