0005-dataviz-add-new-filters-cell-60547.patch
combo/apps/dataviz/forms.py | ||
---|---|---|
27 | 27 | |
28 | 28 |
from combo.utils import cache_during_request, requests, spooler |
29 | 29 | |
30 |
from .models import ChartCell, ChartNgCell |
|
30 |
from .models import TIME_FILTERS, ChartCell, ChartNgCell
|
|
31 | 31 | |
32 | 32 | |
33 | 33 |
class ChartForm(forms.ModelForm): |
... | ... | |
169 | 169 |
else: |
170 | 170 |
if not date: |
171 | 171 |
self.add_error(template_field, _('Template does not evaluate to a valid date.')) |
172 | ||
173 | ||
174 |
class ChartNgPartialForm(ChartFiltersMixin, forms.ModelForm): |
|
175 |
class Meta: |
|
176 |
model = ChartNgCell |
|
177 |
fields = ( |
|
178 |
'time_range', |
|
179 |
'time_range_start', |
|
180 |
'time_range_end', |
|
181 |
) |
|
182 | ||
183 |
def __init__(self, *args, **kwargs): |
|
184 |
super().__init__(*args, **kwargs) |
|
185 |
self.fields.update(self.get_filter_fields(self.instance)) |
|
186 |
for field in self.fields.values(): |
|
187 |
field.required = False |
|
188 | ||
189 |
def clean(self): |
|
190 |
for filter_ in self.instance.statistic.filters: |
|
191 |
if filter_['id'] in self.data: |
|
192 |
self.instance.filter_params[filter_['id']] = self.cleaned_data.get(filter_['id']) |
|
193 | ||
194 | ||
195 |
class ChartFiltersForm(ChartFiltersMixin, forms.ModelForm): |
|
196 |
class Meta: |
|
197 |
model = ChartNgCell |
|
198 |
fields = ( |
|
199 |
'time_range', |
|
200 |
'time_range_start', |
|
201 |
'time_range_end', |
|
202 |
) |
|
203 |
widgets = { |
|
204 |
'time_range_start': forms.DateInput(attrs={'type': 'date'}, format='%Y-%m-%d'), |
|
205 |
'time_range_end': forms.DateInput(attrs={'type': 'date'}, format='%Y-%m-%d'), |
|
206 |
} |
|
207 | ||
208 |
def __init__(self, *args, **kwargs): |
|
209 |
page = kwargs.pop('page') |
|
210 |
super().__init__(*args, **kwargs) |
|
211 |
self.fields['time_range'].choices = BLANK_CHOICE_DASH + TIME_FILTERS |
|
212 | ||
213 |
chart_cells = list(ChartNgCell.objects.filter(page=page, statistic__isnull=False).order_by('order')) |
|
214 |
if not chart_cells: |
|
215 |
self.fields.clear() |
|
216 |
return |
|
217 | ||
218 |
first_cell = chart_cells[0] |
|
219 |
for field in self._meta.fields: |
|
220 |
self.fields[field].initial = getattr(first_cell, field) |
|
221 |
dynamic_fields = self.get_filter_fields(first_cell) |
|
222 |
dynamic_fields_values = {k: v for k, v in first_cell.filter_params.items()} |
|
223 | ||
224 |
for cell in chart_cells[1:]: |
|
225 |
cell_filter_fields = self.get_filter_fields(cell) |
|
226 | ||
227 |
# keep only common fields |
|
228 |
dynamic_fields = {k: v for k, v in dynamic_fields.items() if k in cell_filter_fields} |
|
229 | ||
230 |
# keep only same value fields |
|
231 |
for field, value in cell.filter_params.items(): |
|
232 |
if field in dynamic_fields and value != dynamic_fields_values.get(field): |
|
233 |
del dynamic_fields[field] |
|
234 | ||
235 |
if cell.time_range != first_cell.time_range: |
|
236 |
for field in self._meta.fields: |
|
237 |
self.fields.pop(field, None) |
|
238 | ||
239 |
# ensure compatible choices lists |
|
240 |
for field_name, field in cell_filter_fields.items(): |
|
241 |
if field_name in dynamic_fields: |
|
242 |
dynamic_fields[field_name].choices = [ |
|
243 |
x for x in dynamic_fields[field_name].choices if x in field.choices |
|
244 |
] |
|
245 |
if dynamic_fields[field_name].choices == []: |
|
246 |
del dynamic_fields[field_name] |
|
247 | ||
248 |
self.fields.update(dynamic_fields) |
combo/apps/dataviz/migrations/0016_auto_20201215_1624.py | ||
---|---|---|
2 | 2 | |
3 | 3 |
from django.db import migrations, models |
4 | 4 | |
5 |
from combo.apps.dataviz.models import TIME_FILTERS |
|
5 |
from combo.apps.dataviz.models import TIME_FILTERS, TIME_FILTERS_TEMPLATE
|
|
6 | 6 | |
7 | 7 | |
8 | 8 |
class Migration(migrations.Migration): |
... | ... | |
17 | 17 |
name='time_range', |
18 | 18 |
field=models.CharField( |
19 | 19 |
blank=True, |
20 |
choices=TIME_FILTERS, |
|
20 |
choices=TIME_FILTERS + TIME_FILTERS_TEMPLATE,
|
|
21 | 21 |
max_length=20, |
22 | 22 |
verbose_name='Filtering (time)', |
23 | 23 |
), |
combo/apps/dataviz/migrations/0021_chartfilterscell.py | ||
---|---|---|
1 |
# Generated by Django 2.2.19 on 2022-01-18 10:17 |
|
2 | ||
3 |
import django.db.models.deletion |
|
4 |
from django.db import migrations, models |
|
5 | ||
6 | ||
7 |
class Migration(migrations.Migration): |
|
8 | ||
9 |
dependencies = [ |
|
10 |
('data', '0051_link_cell_max_length'), |
|
11 |
('auth', '0011_update_proxy_permissions'), |
|
12 |
('dataviz', '0020_auto_20220118_1103'), |
|
13 |
] |
|
14 | ||
15 |
operations = [ |
|
16 |
migrations.CreateModel( |
|
17 |
name='ChartFiltersCell', |
|
18 |
fields=[ |
|
19 |
( |
|
20 |
'id', |
|
21 |
models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), |
|
22 |
), |
|
23 |
('placeholder', models.CharField(max_length=20)), |
|
24 |
('order', models.PositiveIntegerField()), |
|
25 |
('slug', models.SlugField(blank=True, verbose_name='Slug')), |
|
26 |
( |
|
27 |
'extra_css_class', |
|
28 |
models.CharField( |
|
29 |
blank=True, max_length=100, verbose_name='Extra classes for CSS styling' |
|
30 |
), |
|
31 |
), |
|
32 |
( |
|
33 |
'template_name', |
|
34 |
models.CharField(blank=True, max_length=50, null=True, verbose_name='Cell Template'), |
|
35 |
), |
|
36 |
('public', models.BooleanField(default=True, verbose_name='Public')), |
|
37 |
( |
|
38 |
'restricted_to_unlogged', |
|
39 |
models.BooleanField(default=False, verbose_name='Restrict to unlogged users'), |
|
40 |
), |
|
41 |
('last_update_timestamp', models.DateTimeField(auto_now=True)), |
|
42 |
('groups', models.ManyToManyField(blank=True, to='auth.Group', verbose_name='Groups')), |
|
43 |
('page', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='data.Page')), |
|
44 |
], |
|
45 |
options={ |
|
46 |
'verbose_name': 'Filters', |
|
47 |
}, |
|
48 |
), |
|
49 |
] |
combo/apps/dataviz/models.py | ||
---|---|---|
158 | 158 |
) |
159 | 159 | |
160 | 160 | |
161 |
TIME_FILTERS = (
|
|
161 |
TIME_FILTERS = [
|
|
162 | 162 |
('previous-year', _('Previous year')), |
163 | 163 |
('current-year', _('Current year')), |
164 | 164 |
('next-year', _('Next year')), |
... | ... | |
169 | 169 |
('current-week', _('Current week')), |
170 | 170 |
('next-week', _('Next week')), |
171 | 171 |
('range', _('Free range (date)')), |
172 |
('range-template', _('Free range (template)')), |
|
173 |
) |
|
172 |
] |
|
173 |
TIME_FILTERS_TEMPLATE = [('range-template', _('Free range (template)'))] |
|
174 | 174 | |
175 | 175 | |
176 | 176 |
@register_cell_class |
... | ... | |
192 | 192 |
_('Filtering (time)'), |
193 | 193 |
max_length=20, |
194 | 194 |
blank=True, |
195 |
choices=TIME_FILTERS, |
|
195 |
choices=TIME_FILTERS + TIME_FILTERS_TEMPLATE,
|
|
196 | 196 |
) |
197 | 197 |
time_range_start = models.DateField(_('From'), null=True, blank=True) |
198 | 198 |
time_range_end = models.DateField(_('To'), null=True, blank=True) |
... | ... | |
678 | 678 |
data['x_labels'] = x_labels |
679 | 679 |
for i, serie in enumerate(data['series']): |
680 | 680 |
serie['data'] = [values[i] for values in aggregates.values()] |
681 | ||
682 | ||
683 |
@register_cell_class |
|
684 |
class ChartFiltersCell(CellBase): |
|
685 |
title = _('Filters') |
|
686 |
default_template_name = 'combo/chart-filters.html' |
|
687 |
max_one_by_page = True |
|
688 | ||
689 |
class Meta: |
|
690 |
verbose_name = _('Filters') |
|
691 | ||
692 |
@classmethod |
|
693 |
def is_enabled(cls): |
|
694 |
return settings.STATISTICS_PROVIDERS |
|
695 | ||
696 |
def get_cell_extra_context(self, context): |
|
697 |
from .forms import ChartFiltersForm |
|
698 | ||
699 |
ctx = super().get_cell_extra_context(context) |
|
700 |
ctx['form'] = ChartFiltersForm(page=self.page) |
|
701 |
return ctx |
combo/apps/dataviz/templates/combo/chart-filters.html | ||
---|---|---|
1 |
{% load i18n %} |
|
2 | ||
3 |
{% block cell-content %} |
|
4 |
<h2>{{ cell.title }}</h2> |
|
5 | ||
6 |
<div> |
|
7 |
{% if form.fields %} |
|
8 |
<form method='get' enctype='multipart/form-data' id='chart-filters'> |
|
9 |
{{ form.as_p }} |
|
10 |
<div class='buttons'> |
|
11 |
<button class='submit-button'>{% trans 'Refresh' %}</button> |
|
12 |
</div> |
|
13 |
</form> |
|
14 |
{% else %} |
|
15 |
<p> |
|
16 |
{% blocktrans trimmed %} |
|
17 |
No filters are available. Note that only filters that are shared between all chart cells will appear. Furthermore, in case they have a value, it must be the same accross all cells. |
|
18 |
{% endblocktrans %} |
|
19 |
</p> |
|
20 |
{% endif %} |
|
21 |
</div> |
|
22 | ||
23 | ||
24 |
<script> |
|
25 |
$(function () { |
|
26 |
start_field = $('#id_time_range_start'); |
|
27 |
end_field = $('#id_time_range_end'); |
|
28 |
$('#id_time_range').change(function() { |
|
29 |
if(this.value == 'range') { |
|
30 |
start_field.parent().show(); |
|
31 |
end_field.parent().show(); |
|
32 |
} else { |
|
33 |
start_field.parent().hide(); |
|
34 |
end_field.parent().hide(); |
|
35 |
} |
|
36 |
}).change(); |
|
37 |
$('#chart-filters').submit(function(e) { |
|
38 |
e.preventDefault(); |
|
39 |
$(window).trigger('combo:refresh-graphs'); |
|
40 |
}); |
|
41 |
}); |
|
42 |
</script> |
|
43 |
{% endblock %} |
combo/apps/dataviz/templates/combo/chartngcell.html | ||
---|---|---|
13 | 13 |
var chart_cell = $('#chart-{{cell.id}}').parent(); |
14 | 14 |
var new_width = Math.floor($(chart_cell).width()); |
15 | 15 |
var ratio = new_width / last_width; |
16 |
var filter_params = $('#chart-filters').serialize(); |
|
16 | 17 |
if (ratio > 1.2 || ratio < 0.8) { |
17 | 18 |
$('#chart-{{cell.id}}').attr('src', |
18 |
"{% url 'combo-dataviz-graph' cell=cell.id %}?width=" + new_width); |
|
19 |
"{% url 'combo-dataviz-graph' cell=cell.id %}?width=" + new_width + '&' + filter_params);
|
|
19 | 20 |
last_width = new_width; |
20 | 21 |
} |
21 | 22 |
}).trigger('combo:resize-graphs'); |
23 |
$(window).on('combo:refresh-graphs', function() { |
|
24 |
var filter_params = $('#chart-filters').serialize(); |
|
25 |
$('#chart-{{cell.id}}').attr('src', |
|
26 |
"{% url 'combo-dataviz-graph' cell=cell.id %}?width=" + last_width + '&' + filter_params); |
|
27 |
}); |
|
22 | 28 |
}); |
23 | 29 |
</script> |
24 | 30 |
{% endif %} |
combo/apps/dataviz/views.py | ||
---|---|---|
23 | 23 | |
24 | 24 |
from combo.utils import get_templated_url, requests |
25 | 25 | |
26 |
from .forms import ChartNgPartialForm |
|
26 | 27 |
from .models import ChartNgCell, Gauge, UnsupportedDataSet |
27 | 28 | |
28 | 29 | |
... | ... | |
49 | 50 |
return super().dispatch(request, *args, **kwargs) |
50 | 51 | |
51 | 52 |
def get(self, request, *args, **kwargs): |
53 |
form = ChartNgPartialForm(request.GET, instance=self.cell) |
|
54 |
if not form.is_valid(): |
|
55 |
return self.svg_error(_('Wrong parameters.')) |
|
56 | ||
52 | 57 |
try: |
53 |
chart = self.cell.get_chart(
|
|
58 |
chart = form.instance.get_chart(
|
|
54 | 59 |
width=int(request.GET['width']) if request.GET.get('width') else None, |
55 | 60 |
height=int(request.GET['height']) if request.GET.get('height') else int(self.cell.height), |
56 | 61 |
) |
tests/test_dataviz.py | ||
---|---|---|
10 | 10 |
from httmock import HTTMock, remember_called, urlmatch, with_httmock |
11 | 11 |
from requests.exceptions import HTTPError |
12 | 12 | |
13 |
from combo.apps.dataviz.models import ChartNgCell, Gauge, Statistic, UnsupportedDataSet |
|
13 |
from combo.apps.dataviz.models import ChartFiltersCell, ChartNgCell, Gauge, Statistic, UnsupportedDataSet
|
|
14 | 14 |
from combo.data.models import Page, ValidityInfo |
15 | 15 | |
16 | 16 |
from .test_public import login |
... | ... | |
1743 | 1743 |
assert len(chart.x_labels) == 1 |
1744 | 1744 |
assert chart.x_labels == ['W53-2020'] |
1745 | 1745 |
assert chart.raw_series == [([19], {'title': 'Serie 1'})] |
1746 | ||
1747 | ||
1748 |
@with_httmock(new_api_mock) |
|
1749 |
def test_chart_filters_cell(new_api_statistics, app, admin_user, nocache): |
|
1750 |
page = Page.objects.create(title='One', slug='index') |
|
1751 |
ChartFiltersCell.objects.create(page=page, order=1, placeholder='content') |
|
1752 |
app = login(app) |
|
1753 |
resp = app.get('/') |
|
1754 |
assert 'No filters are available' in resp.text |
|
1755 | ||
1756 |
# add unconfigured chart |
|
1757 |
first_cell = ChartNgCell.objects.create(page=page, order=2, placeholder='content') |
|
1758 |
resp = app.get('/') |
|
1759 |
assert 'No filters are available' in resp.text |
|
1760 | ||
1761 |
# add statistics to chart |
|
1762 |
first_cell.statistic = Statistic.objects.get(slug='one-serie') |
|
1763 |
first_cell.save() |
|
1764 |
resp = app.get('/') |
|
1765 |
assert len(resp.form.fields) == 7 |
|
1766 |
assert 'time_range_start' in resp.form.fields |
|
1767 |
assert 'time_range_end' in resp.form.fields |
|
1768 | ||
1769 |
time_range_field = resp.form['time_range'] |
|
1770 |
assert time_range_field.value == '' |
|
1771 |
assert time_range_field.options == [ |
|
1772 |
('', True, '---------'), |
|
1773 |
('previous-year', False, 'Previous year'), |
|
1774 |
('current-year', False, 'Current year'), |
|
1775 |
('next-year', False, 'Next year'), |
|
1776 |
('previous-month', False, 'Previous month'), |
|
1777 |
('current-month', False, 'Current month'), |
|
1778 |
('next-month', False, 'Next month'), |
|
1779 |
('previous-week', False, 'Previous week'), |
|
1780 |
('current-week', False, 'Current week'), |
|
1781 |
('next-week', False, 'Next week'), |
|
1782 |
('range', False, 'Free range (date)'), |
|
1783 |
] |
|
1784 | ||
1785 |
time_interval_field = resp.form['time_interval'] |
|
1786 |
assert time_interval_field.value == 'month' |
|
1787 |
assert time_interval_field.options == [ |
|
1788 |
('day', False, 'Day'), |
|
1789 |
('month', True, 'Month'), |
|
1790 |
('year', False, 'Year'), |
|
1791 |
('week', False, 'Week'), |
|
1792 |
('weekday', False, 'Week day'), |
|
1793 |
] |
|
1794 | ||
1795 |
service_field = resp.form['service'] |
|
1796 |
assert service_field.value == 'chrono' |
|
1797 |
assert service_field.options == [ |
|
1798 |
('', False, '---------'), |
|
1799 |
('chrono', True, 'Chrono'), |
|
1800 |
('combo', False, 'Combo'), |
|
1801 |
] |
|
1802 | ||
1803 |
ou_field = resp.form['ou'] |
|
1804 |
assert ou_field.value == '' |
|
1805 |
assert ou_field.options == [ |
|
1806 |
('', True, '---------'), |
|
1807 |
('default', False, 'Default OU'), |
|
1808 |
('other', False, 'Other OU'), |
|
1809 |
] |
|
1810 | ||
1811 |
# adding new cell with same statistics changes nothing |
|
1812 |
cell = ChartNgCell(page=page, order=3, placeholder='content') |
|
1813 |
cell.statistic = Statistic.objects.get(slug='one-serie') |
|
1814 |
cell.save() |
|
1815 |
old_resp = resp |
|
1816 |
resp = app.get('/') |
|
1817 |
for field in ('time_range', 'time_interval', 'service', 'ou'): |
|
1818 |
assert resp.form[field].options == old_resp.form[field].options |
|
1819 | ||
1820 |
# changing one filter value makes it disappear |
|
1821 |
cell.filter_params = {'ou': 'default'} |
|
1822 |
cell.save() |
|
1823 |
resp = app.get('/') |
|
1824 |
assert 'ou' not in resp.form.fields |
|
1825 |
for field in ('time_range', 'time_interval', 'service'): |
|
1826 |
assert resp.form[field].options == old_resp.form[field].options |
|
1827 | ||
1828 |
# setting the same value for the other cell makes it appear again |
|
1829 |
first_cell.filter_params = {'ou': 'default'} |
|
1830 |
first_cell.save() |
|
1831 |
resp = app.get('/') |
|
1832 |
assert resp.form['ou'].value == 'default' |
|
1833 | ||
1834 |
# changing statistics type of cell remove some fields |
|
1835 |
cell.statistic = Statistic.objects.get(slug='daily') |
|
1836 |
cell.save() |
|
1837 |
resp = app.get('/') |
|
1838 |
assert 'ou' not in resp.form.fields |
|
1839 |
assert 'service' not in resp.form.fields |
|
1840 |
for field in ('time_range', 'time_interval'): |
|
1841 |
assert resp.form[field].options == old_resp.form[field].options |
|
1842 | ||
1843 |
# changing time_interval value makes interval fields disappear |
|
1844 |
cell.time_range = 'next-year' |
|
1845 |
cell.save() |
|
1846 |
old_resp = resp |
|
1847 |
resp = app.get('/') |
|
1848 |
assert 'time_range' not in resp.form.fields |
|
1849 |
assert 'time_range_start' not in resp.form.fields |
|
1850 |
assert 'time_range_end' not in resp.form.fields |
|
1851 |
assert resp.form['time_interval'].options == old_resp.form['time_interval'].options |
|
1852 | ||
1853 |
# setting the same value for the other cell makes it appear again |
|
1854 |
first_cell.time_range = 'next-year' |
|
1855 |
first_cell.save() |
|
1856 |
resp = app.get('/') |
|
1857 |
assert resp.form['time_range'].value == 'next-year' |
|
1858 |
assert resp.form['time_interval'].options == old_resp.form['time_interval'].options |
|
1859 | ||
1860 |
# only common choices are shown |
|
1861 |
first_cell.statistic.filters[0]['options'].remove({'id': 'day', 'label': 'Day'}) |
|
1862 |
first_cell.statistic.save() |
|
1863 |
resp = app.get('/') |
|
1864 |
assert resp.form['time_interval'].options == [ |
|
1865 |
('month', True, 'Month'), |
|
1866 |
('year', False, 'Year'), |
|
1867 |
] |
|
1868 | ||
1869 |
# if no common choices exist, field is removed |
|
1870 |
first_cell.statistic.filters[0]['options'] = [{'id': 'random', 'label': 'Random'}] |
|
1871 |
first_cell.statistic.save() |
|
1872 |
resp = app.get('/') |
|
1873 |
assert 'time_interval' not in resp.form.fields |
|
1874 |
assert resp.form['time_range'].value == 'next-year' |
|
1875 | ||
1876 |
# form is not shown if no common filters exist |
|
1877 |
first_cell.time_range = 'current-year' |
|
1878 |
first_cell.save() |
|
1879 |
resp = app.get('/') |
|
1880 |
assert 'No filters are available' in resp.text |
|
1881 | ||
1882 | ||
1883 |
@with_httmock(new_api_mock) |
|
1884 |
def test_chartng_cell_api_view_get_parameters(app, normal_user, new_api_statistics, nocache): |
|
1885 |
page = Page.objects.create(title='One', slug='index') |
|
1886 |
cell = ChartNgCell(page=page, order=1, placeholder='content') |
|
1887 |
cell.statistic = Statistic.objects.get(slug='one-serie') |
|
1888 |
cell.save() |
|
1889 | ||
1890 |
location = '/api/dataviz/graph/%s/' % cell.id |
|
1891 |
app.get(location) |
|
1892 |
request = new_api_mock.call['requests'][0] |
|
1893 |
assert 'time_interval=' not in request.url |
|
1894 |
assert 'ou=' not in request.url |
|
1895 | ||
1896 |
cell.filter_params = {'time_interval': 'month', 'ou': 'default'} |
|
1897 |
cell.save() |
|
1898 |
app.get(location) |
|
1899 |
request = new_api_mock.call['requests'][1] |
|
1900 |
assert 'time_interval=month' in request.url |
|
1901 |
assert 'ou=default' in request.url |
|
1902 | ||
1903 |
app.get(location + '?time_interval=year') |
|
1904 |
request = new_api_mock.call['requests'][2] |
|
1905 |
assert 'time_interval=year' in request.url |
|
1906 |
assert 'ou=default' in request.url |
|
1907 | ||
1908 |
cell.filter_params.clear() |
|
1909 |
cell.statistic = Statistic.objects.get(slug='filter-multiple') |
|
1910 |
cell.save() |
|
1911 |
app.get(location + '?color=green&color=blue') |
|
1912 |
request = new_api_mock.call['requests'][3] |
|
1913 |
assert 'color=green&color=blue' in request.url |
|
1914 | ||
1915 |
# unknown params |
|
1916 |
app.get(location + '?time_interval=month&ou=default') |
|
1917 |
request = new_api_mock.call['requests'][4] |
|
1918 |
assert 'time_interval=' not in request.url |
|
1919 |
assert 'ou=' not in request.url |
|
1920 | ||
1921 |
# wrong params |
|
1922 |
resp = app.get(location + '?time_range_start=xxx') |
|
1923 |
assert 'Wrong parameters' in resp.text |
|
1924 |
assert len(new_api_mock.call['requests']) == 5 |
tests/test_manager.py | ||
---|---|---|
926 | 926 |
resp.form['site_file'] = Upload('site-export.json', site_export, 'application/json') |
927 | 927 |
with CaptureQueriesContext(connection) as ctx: |
928 | 928 |
resp = resp.form.submit() |
929 |
assert len(ctx.captured_queries) in [303, 304]
|
|
929 |
assert len(ctx.captured_queries) in [308, 309]
|
|
930 | 930 |
assert Page.objects.count() == 4 |
931 | 931 |
assert PageSnapshot.objects.all().count() == 4 |
932 | 932 | |
... | ... | |
937 | 937 |
resp.form['site_file'] = Upload('site-export.json', site_export, 'application/json') |
938 | 938 |
with CaptureQueriesContext(connection) as ctx: |
939 | 939 |
resp = resp.form.submit() |
940 |
assert len(ctx.captured_queries) == 273
|
|
940 |
assert len(ctx.captured_queries) == 277
|
|
941 | 941 |
assert set(Page.objects.get(slug='one').related_cells['cell_types']) == {'data_textcell', 'data_linkcell'} |
942 | 942 |
assert Page.objects.count() == 4 |
943 | 943 |
assert LinkCell.objects.count() == 2 |
... | ... | |
2276 | 2276 | |
2277 | 2277 |
with CaptureQueriesContext(connection) as ctx: |
2278 | 2278 |
resp2 = resp.click('view', index=1) |
2279 |
assert len(ctx.captured_queries) == 70
|
|
2279 |
assert len(ctx.captured_queries) == 71
|
|
2280 | 2280 |
assert Page.snapshots.latest('pk').related_cells == {'cell_types': ['data_textcell']} |
2281 | 2281 |
assert resp2.text.index('Hello world') < resp2.text.index('Foobar3') |
2282 | 2282 | |
... | ... | |
2337 | 2337 |
resp = resp.click('restore', index=6) |
2338 | 2338 |
with CaptureQueriesContext(connection) as ctx: |
2339 | 2339 |
resp = resp.form.submit().follow() |
2340 |
assert len(ctx.captured_queries) == 144
|
|
2340 |
assert len(ctx.captured_queries) == 146
|
|
2341 | 2341 | |
2342 | 2342 |
resp2 = resp.click('See online') |
2343 | 2343 |
assert resp2.text.index('Foobar1') < resp2.text.index('Foobar2') < resp2.text.index('Foobar3') |
tests/test_search.py | ||
---|---|---|
1420 | 1420 |
assert IndexedCell.objects.count() == 50 |
1421 | 1421 |
with CaptureQueriesContext(connection) as ctx: |
1422 | 1422 |
index_site() |
1423 |
assert len(ctx.captured_queries) == 224
|
|
1423 |
assert len(ctx.captured_queries) == 225
|
|
1424 | 1424 | |
1425 | 1425 |
SearchCell.objects.create( |
1426 | 1426 |
page=page, placeholder='content', order=0, _search_services={'data': ['search1']} |
1427 |
- |