0001-add-support-for-string-columns-fixes-29768.patch
bijoe/schemas.py | ||
---|---|---|
254 | 254 |
filter_values = [filter_values] |
255 | 255 |
if not filter_values: |
256 | 256 |
return '', [] |
257 |
is_none = None in filter_values |
|
258 |
filter_values = [v for v in filter_values if v is not None] |
|
257 | 259 |
if self.type == 'integer': |
258 |
values = map(int, filter_values)
|
|
260 |
values = [int(v) for v in filter_values]
|
|
259 | 261 |
else: |
260 | 262 |
values = filter_values |
261 | 263 |
s = ', '.join(['%s'] * len(values)) |
262 | 264 |
if self.filter_expression: |
263 |
return self.filter_expression % s, values |
|
264 |
return '%s IN (%s)' % (value, s), values |
|
265 |
expression = self.filter_expression % s |
|
266 |
else: |
|
267 |
expression = '%s IN (%s)' % (value, s) |
|
268 |
if is_none: |
|
269 |
expression = '((%s) OR (%s IS NULL))' % (expression, value) |
|
270 |
return expression, values |
|
265 | 271 | |
266 | 272 | |
267 | 273 |
def join_kind(kind): |
bijoe/templates/bijoe/cube_table.html | ||
---|---|---|
13 | 13 |
<tr> |
14 | 14 |
{% for value in row %} |
15 | 15 |
{% comment %}Only django 1.10 allow is None/True/False{% endcomment %} |
16 |
<td>{% if value|stringformat:"r" == "None" %}0{% elif value|stringformat:"r" == "True" %}{% trans "Oui" %}{% elif value|stringformat:"r" == "False" %}{% trans "Non" %}{% else %}{{ value }}{% endif %}</td>
|
|
16 |
<td>{{ value }}</td>
|
|
17 | 17 |
{% endfor %} |
18 | 18 |
</tr> |
19 | 19 |
{% endfor %} |
bijoe/visualization/forms.py | ||
---|---|---|
15 | 15 |
# You should have received a copy of the GNU Affero General Public License |
16 | 16 |
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 | 17 | |
18 | ||
18 | 19 |
from django import forms |
19 | 20 |
from django.core.exceptions import ValidationError |
20 | 21 |
from django.utils.translation import ugettext as _ |
21 | 22 |
from django.utils.safestring import mark_safe |
23 |
from django.utils import six |
|
22 | 24 |
from django.forms import ModelForm, TextInput, NullBooleanField |
23 | 25 |
from django.conf import settings |
24 | 26 | |
... | ... | |
183 | 185 |
self.base_fields[field_name] = NullBooleanField( |
184 | 186 |
label=dimension.label.capitalize(), required=False) |
185 | 187 |
else: |
186 |
self.base_fields[field_name] = forms.MultipleChoiceField( |
|
188 |
members = [] |
|
189 |
for _id, label in dimension.members: |
|
190 |
members.append((_id, six.text_type(_id), label)) |
|
191 |
members.append((None, '__none__', _('None'))) |
|
192 | ||
193 |
def coercion_function(members): |
|
194 |
def f(v): |
|
195 |
for value, s, label in members: |
|
196 |
if v == s: |
|
197 |
return value |
|
198 |
return None |
|
199 |
return f |
|
200 | ||
201 |
self.base_fields[field_name] = forms.TypedMultipleChoiceField( |
|
187 | 202 |
label=dimension.label.capitalize(), |
188 |
choices=dimension.members, |
|
203 |
choices=[(s, label) for v, s, label in members], |
|
204 |
coerce=coercion_function(members), |
|
189 | 205 |
required=False, |
190 | 206 |
widget=build_select2_multiple_widget()) |
191 | 207 |
bijoe/visualization/utils.py | ||
---|---|---|
159 | 159 |
if not s: |
160 | 160 |
s = 'moins d\'1 heure' |
161 | 161 |
value = s |
162 |
elif value is not None and cell['type'] == 'bool': |
|
163 |
value = _('Yes') if value else _('No') |
|
164 |
elif value is None and cell['type'] in ('duration','integer'): |
|
165 |
value = 0 |
|
166 |
elif value is None and cell['type'] != 'integer': |
|
167 |
value = _('None') |
|
162 | 168 |
cell['value'] = value |
163 | 169 |
return data |
164 | 170 | |
... | ... | |
179 | 185 |
def table(self): |
180 | 186 |
table = [] |
181 | 187 |
if len(self.drilldown) == 2: |
188 |
if self.measure.type == 'integer': |
|
189 |
default = 0 |
|
190 |
elif self.measure.type == 'duration': |
|
191 |
default = '0 s' |
|
192 |
elif self.measure.type == 'percent': |
|
193 |
default = '0 %' |
|
194 |
else: |
|
195 |
raise NotImplementedError(self.measure.type) |
|
196 | ||
182 | 197 |
x_labels = [x.label for x in self.drilldown_x.members] |
183 | 198 |
y_labels = [y.label for y in self.drilldown_y.members] |
184 | 199 |
used_x_label = set() |
185 | 200 |
used_y_label = set() |
186 | 201 | |
187 |
grid = {(x, y): None for x in x_labels for y in y_labels}
|
|
202 |
grid = {(x, y): default for x in x_labels for y in y_labels}
|
|
188 | 203 | |
189 | 204 |
for row in self.stringified(): |
190 | 205 |
x_label = unicode(row[0]['value']) |
tests/fixtures/schema1/01_schema.json | ||
---|---|---|
157 | 157 |
"value": "outercategory.id", |
158 | 158 |
"order_by": "outercategory.ord", |
159 | 159 |
"value_label": "outercategory.label" |
160 |
}, |
|
161 |
{ |
|
162 |
"name": "string", |
|
163 |
"label": "String", |
|
164 |
"type": "string", |
|
165 |
"value": "string" |
|
160 | 166 |
} |
161 | 167 |
], |
162 | 168 |
"measures": [ |
tests/fixtures/schema1/01_schema.sql | ||
---|---|---|
25 | 25 |
innersubcategory_id integer references schema1.subcategory(id), |
26 | 26 |
leftsubcategory_id integer references schema1.subcategory(id), |
27 | 27 |
rightsubcategory_id integer references schema1.subcategory(id), |
28 |
outersubcategory_id integer references schema1.subcategory(id) |
|
28 |
outersubcategory_id integer references schema1.subcategory(id), |
|
29 |
string varchar |
|
29 | 30 |
); |
30 | 31 | |
31 | 32 |
INSERT INTO category (ord, label) VALUES |
... | ... | |
45 | 46 |
(3, 0, 'subé9'); |
46 | 47 | |
47 | 48 | |
48 |
INSERT INTO facts (date, datetime, integer, boolean, cnt, innersubcategory_id, leftsubcategory_id, rightsubcategory_id, outersubcategory_id) VALUES |
|
49 |
('2017-01-01', '2017-01-01 10:00', 1, FALSE, 10, 1, 1, 1, 1), |
|
50 |
('2017-01-02', '2017-01-02 10:00', 1, TRUE, 10, 3, 3, 3, 3), |
|
51 |
('2017-01-03', '2017-01-03 10:00', 1, FALSE, 10, NULL, NULL, NULL, NULL), |
|
52 |
('2017-01-04', '2017-01-04 10:00', 1, FALSE, 10, 1, 1, 1, 1), |
|
53 |
('2017-01-05', '2017-01-05 10:00', 1, TRUE, 10, 1, 1, 1, 1), |
|
54 |
('2017-01-06', '2017-01-06 10:00', 1, FALSE, 10, 1, 1, 1, 1), |
|
55 |
('2017-01-07', '2017-01-07 10:00', 1, TRUE, 10, 1, 1, 1, 1), |
|
56 |
('2017-01-08', '2017-01-08 10:00', 1, FALSE, 10, 1, 1, 1, 1), |
|
57 |
('2017-01-09', '2017-01-09 10:00', 1, TRUE, 10, 1, 1, 1, 1), |
|
58 |
('2017-01-10', '2017-01-10 10:00', 1, FALSE, 10, 1, 1, 1, 1), |
|
59 |
('2017-02-01', '2017-02-01 10:00', 1, TRUE, 10, 1, 1, 1, 1), |
|
60 |
('2017-03-01', '2017-03-01 10:00', 1, FALSE, 10, 1, 1, 1, 1), |
|
61 |
('2017-04-01', '2017-04-01 10:00', 1, TRUE, 10, 1, 1, 1, 1), |
|
62 |
('2017-05-01', '2017-05-01 10:00', 1, FALSE, 10, 1, 1, 1, 1), |
|
63 |
('2017-06-01', '2017-06-01 10:00', 1, TRUE, 10, 1, 1, 1, 1), |
|
64 |
('2017-07-01', '2017-07-01 10:00', 1, FALSE, 10, 1, 1, 1, 1), |
|
65 |
('2017-08-01', '2017-08-01 10:00', 1, TRUE, 10, 1, 1, 1, 1); |
|
49 |
INSERT INTO facts (date, datetime, integer, boolean, cnt, innersubcategory_id, leftsubcategory_id, rightsubcategory_id, outersubcategory_id, string) VALUES |
|
50 |
('2017-01-01', '2017-01-01 10:00', 1, FALSE, 10, 1, 1, 1, 1, 'a'), |
|
51 |
('2017-01-02', '2017-01-02 10:00', 1, TRUE, 10, 3, 3, 3, 3, 'b'), |
|
52 |
('2017-01-03', '2017-01-03 10:00', 1, FALSE, 10, NULL, NULL, NULL, NULL, 'a'), |
|
53 |
('2017-01-04', '2017-01-04 10:00', 1, FALSE, 10, 1, 1, 1, 1, 'a'), |
|
54 |
('2017-01-05', '2017-01-05 10:00', 1, TRUE, 10, 1, 1, 1, 1, 'c'), |
|
55 |
('2017-01-06', '2017-01-06 10:00', 1, FALSE, 10, 1, 1, 1, 1, NULL), |
|
56 |
('2017-01-07', '2017-01-07 10:00', 1, TRUE, 10, 1, 1, 1, 1, 'a'), |
|
57 |
('2017-01-08', '2017-01-08 10:00', 1, FALSE, 10, 1, 1, 1, 1, 'a'), |
|
58 |
('2017-01-09', '2017-01-09 10:00', 1, TRUE, 10, 1, 1, 1, 1, 'a'), |
|
59 |
('2017-01-10', '2017-01-10 10:00', 1, FALSE, 10, 1, 1, 1, 1, 'a'), |
|
60 |
('2017-02-01', '2017-02-01 10:00', 1, TRUE, 10, 1, 1, 1, 1, 'a'), |
|
61 |
('2017-03-01', '2017-03-01 10:00', 1, FALSE, 10, 1, 1, 1, 1, 'c'), |
|
62 |
('2017-04-01', '2017-04-01 10:00', 1, TRUE, 10, 1, 1, 1, 1, 'a'), |
|
63 |
('2017-05-01', '2017-05-01 10:00', 1, FALSE, 10, 1, 1, 1, 1, 'a'), |
|
64 |
('2017-06-01', '2017-06-01 10:00', 1, TRUE, 10, 1, 1, 1, 1, 'c'), |
|
65 |
('2017-07-01', '2017-07-01 10:00', 1, FALSE, 10, 1, 1, 1, 1, 'a'), |
|
66 |
('2017-08-01', '2017-08-01 10:00', 1, TRUE, 10, 1, 1, 1, 1, 'b'); |
tests/test_schema1.py | ||
---|---|---|
68 | 68 |
form.set('filter__boolean', [o[0] for o in form.fields['filter__boolean'][0].options if o[2] == 'Oui'][0]) |
69 | 69 |
response = form.submit('visualize') |
70 | 70 |
assert get_table(response) == [['Boolean', 'Oui'], ['number of rows', '8']] |
71 | ||
72 | ||
73 |
def test_string_dimension(schema1, app, admin): |
|
74 |
login(app, admin) |
|
75 |
response = app.get('/').follow() |
|
76 |
response = response.click('Facts 1') |
|
77 |
form = response.form |
|
78 |
form.set('representation', 'table') |
|
79 |
form.set('measure', 'simple_count') |
|
80 |
form.set('drilldown_x', 'string') |
|
81 |
response = form.submit('visualize') |
|
82 |
assert get_table(response) == [['String', 'a', 'b', 'c', 'Aucun(e)'], ['number of rows', '11', '2', '3', '1']] |
|
83 |
form.set('filter__string', ['a', 'b', '__none__']) |
|
84 |
response = form.submit('visualize') |
|
85 |
assert get_table(response) == [['String', 'a', 'b', 'Aucun(e)'], ['number of rows', '11', '2', '1']] |
tox.ini | ||
---|---|---|
25 | 25 |
pytest-cov |
26 | 26 |
pytest-django |
27 | 27 |
pytest-freezegun |
28 |
pytest-random |
|
28 | 29 |
WebTest |
29 | 30 |
django-webtest<1.9.3 |
30 | 31 |
pyquery |
31 |
- |