diff --git a/bijoe/schemas.py b/bijoe/schemas.py
index f1f00cb..bc0b53a 100644
--- a/bijoe/schemas.py
+++ b/bijoe/schemas.py
@@ -254,14 +254,20 @@ class Dimension(Base):
filter_values = [filter_values]
if not filter_values:
return '', []
+ is_none = None in filter_values
+ filter_values = [v for v in filter_values if v is not None]
if self.type == 'integer':
- values = map(int, filter_values)
+ values = [int(v) for v in filter_values]
else:
values = filter_values
s = ', '.join(['%s'] * len(values))
if self.filter_expression:
- return self.filter_expression % s, values
- return '%s IN (%s)' % (value, s), values
+ expression = self.filter_expression % s
+ else:
+ expression = '%s IN (%s)' % (value, s)
+ if is_none:
+ expression = '((%s) OR (%s IS NULL))' % (expression, value)
+ return expression, values
def join_kind(kind):
diff --git a/bijoe/templates/bijoe/cube_table.html b/bijoe/templates/bijoe/cube_table.html
index d75728c..4f24dc4 100644
--- a/bijoe/templates/bijoe/cube_table.html
+++ b/bijoe/templates/bijoe/cube_table.html
@@ -13,7 +13,7 @@
{% for value in row %}
{% comment %}Only django 1.10 allow is None/True/False{% endcomment %}
- {% if value|stringformat:"r" == "None" %}0{% elif value|stringformat:"r" == "True" %}{% trans "Oui" %}{% elif value|stringformat:"r" == "False" %}{% trans "Non" %}{% else %}{{ value }}{% endif %} |
+ {{ value }} |
{% endfor %}
{% endfor %}
diff --git a/bijoe/visualization/forms.py b/bijoe/visualization/forms.py
index e46c89c..6e34d7b 100644
--- a/bijoe/visualization/forms.py
+++ b/bijoe/visualization/forms.py
@@ -15,10 +15,12 @@
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
+
from django import forms
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext as _
from django.utils.safestring import mark_safe
+from django.utils import six
from django.forms import ModelForm, TextInput, NullBooleanField
from django.conf import settings
@@ -183,9 +185,23 @@ class CubeForm(forms.Form):
self.base_fields[field_name] = NullBooleanField(
label=dimension.label.capitalize(), required=False)
else:
- self.base_fields[field_name] = forms.MultipleChoiceField(
+ members = []
+ for _id, label in dimension.members:
+ members.append((_id, six.text_type(_id), label))
+ members.append((None, '__none__', _('None')))
+
+ def coercion_function(members):
+ def f(v):
+ for value, s, label in members:
+ if v == s:
+ return value
+ return None
+ return f
+
+ self.base_fields[field_name] = forms.TypedMultipleChoiceField(
label=dimension.label.capitalize(),
- choices=dimension.members,
+ choices=[(s, label) for v, s, label in members],
+ coerce=coercion_function(members),
required=False,
widget=build_select2_multiple_widget())
diff --git a/bijoe/visualization/utils.py b/bijoe/visualization/utils.py
index 2fdd4f4..db6077c 100644
--- a/bijoe/visualization/utils.py
+++ b/bijoe/visualization/utils.py
@@ -159,6 +159,12 @@ class Visualization(object):
if not s:
s = 'moins d\'1 heure'
value = s
+ elif value is not None and cell['type'] == 'bool':
+ value = _('Yes') if value else _('No')
+ elif value is None and cell['type'] in ('duration','integer'):
+ value = 0
+ elif value is None and cell['type'] != 'integer':
+ value = _('None')
cell['value'] = value
return data
@@ -179,12 +185,21 @@ class Visualization(object):
def table(self):
table = []
if len(self.drilldown) == 2:
+ if self.measure.type == 'integer':
+ default = 0
+ elif self.measure.type == 'duration':
+ default = '0 s'
+ elif self.measure.type == 'percent':
+ default = '0 %'
+ else:
+ raise NotImplementedError(self.measure.type)
+
x_labels = [x.label for x in self.drilldown_x.members]
y_labels = [y.label for y in self.drilldown_y.members]
used_x_label = set()
used_y_label = set()
- grid = {(x, y): None for x in x_labels for y in y_labels}
+ grid = {(x, y): default for x in x_labels for y in y_labels}
for row in self.stringified():
x_label = unicode(row[0]['value'])
diff --git a/tests/fixtures/schema1/01_schema.json b/tests/fixtures/schema1/01_schema.json
index 823dfbe..64c33d3 100644
--- a/tests/fixtures/schema1/01_schema.json
+++ b/tests/fixtures/schema1/01_schema.json
@@ -157,6 +157,12 @@
"value": "outercategory.id",
"order_by": "outercategory.ord",
"value_label": "outercategory.label"
+ },
+ {
+ "name": "string",
+ "label": "String",
+ "type": "string",
+ "value": "string"
}
],
"measures": [
diff --git a/tests/fixtures/schema1/01_schema.sql b/tests/fixtures/schema1/01_schema.sql
index da77db4..ecf1242 100644
--- a/tests/fixtures/schema1/01_schema.sql
+++ b/tests/fixtures/schema1/01_schema.sql
@@ -25,7 +25,8 @@ CREATE TABLE facts (
innersubcategory_id integer references schema1.subcategory(id),
leftsubcategory_id integer references schema1.subcategory(id),
rightsubcategory_id integer references schema1.subcategory(id),
- outersubcategory_id integer references schema1.subcategory(id)
+ outersubcategory_id integer references schema1.subcategory(id),
+ string varchar
);
INSERT INTO category (ord, label) VALUES
@@ -45,21 +46,21 @@ INSERT INTO subcategory (category_id, ord, label) VALUES
(3, 0, 'subé9');
-INSERT INTO facts (date, datetime, integer, boolean, cnt, innersubcategory_id, leftsubcategory_id, rightsubcategory_id, outersubcategory_id) VALUES
- ('2017-01-01', '2017-01-01 10:00', 1, FALSE, 10, 1, 1, 1, 1),
- ('2017-01-02', '2017-01-02 10:00', 1, TRUE, 10, 3, 3, 3, 3),
- ('2017-01-03', '2017-01-03 10:00', 1, FALSE, 10, NULL, NULL, NULL, NULL),
- ('2017-01-04', '2017-01-04 10:00', 1, FALSE, 10, 1, 1, 1, 1),
- ('2017-01-05', '2017-01-05 10:00', 1, TRUE, 10, 1, 1, 1, 1),
- ('2017-01-06', '2017-01-06 10:00', 1, FALSE, 10, 1, 1, 1, 1),
- ('2017-01-07', '2017-01-07 10:00', 1, TRUE, 10, 1, 1, 1, 1),
- ('2017-01-08', '2017-01-08 10:00', 1, FALSE, 10, 1, 1, 1, 1),
- ('2017-01-09', '2017-01-09 10:00', 1, TRUE, 10, 1, 1, 1, 1),
- ('2017-01-10', '2017-01-10 10:00', 1, FALSE, 10, 1, 1, 1, 1),
- ('2017-02-01', '2017-02-01 10:00', 1, TRUE, 10, 1, 1, 1, 1),
- ('2017-03-01', '2017-03-01 10:00', 1, FALSE, 10, 1, 1, 1, 1),
- ('2017-04-01', '2017-04-01 10:00', 1, TRUE, 10, 1, 1, 1, 1),
- ('2017-05-01', '2017-05-01 10:00', 1, FALSE, 10, 1, 1, 1, 1),
- ('2017-06-01', '2017-06-01 10:00', 1, TRUE, 10, 1, 1, 1, 1),
- ('2017-07-01', '2017-07-01 10:00', 1, FALSE, 10, 1, 1, 1, 1),
- ('2017-08-01', '2017-08-01 10:00', 1, TRUE, 10, 1, 1, 1, 1);
+INSERT INTO facts (date, datetime, integer, boolean, cnt, innersubcategory_id, leftsubcategory_id, rightsubcategory_id, outersubcategory_id, string) VALUES
+ ('2017-01-01', '2017-01-01 10:00', 1, FALSE, 10, 1, 1, 1, 1, 'a'),
+ ('2017-01-02', '2017-01-02 10:00', 1, TRUE, 10, 3, 3, 3, 3, 'b'),
+ ('2017-01-03', '2017-01-03 10:00', 1, FALSE, 10, NULL, NULL, NULL, NULL, 'a'),
+ ('2017-01-04', '2017-01-04 10:00', 1, FALSE, 10, 1, 1, 1, 1, 'a'),
+ ('2017-01-05', '2017-01-05 10:00', 1, TRUE, 10, 1, 1, 1, 1, 'c'),
+ ('2017-01-06', '2017-01-06 10:00', 1, FALSE, 10, 1, 1, 1, 1, NULL),
+ ('2017-01-07', '2017-01-07 10:00', 1, TRUE, 10, 1, 1, 1, 1, 'a'),
+ ('2017-01-08', '2017-01-08 10:00', 1, FALSE, 10, 1, 1, 1, 1, 'a'),
+ ('2017-01-09', '2017-01-09 10:00', 1, TRUE, 10, 1, 1, 1, 1, 'a'),
+ ('2017-01-10', '2017-01-10 10:00', 1, FALSE, 10, 1, 1, 1, 1, 'a'),
+ ('2017-02-01', '2017-02-01 10:00', 1, TRUE, 10, 1, 1, 1, 1, 'a'),
+ ('2017-03-01', '2017-03-01 10:00', 1, FALSE, 10, 1, 1, 1, 1, 'c'),
+ ('2017-04-01', '2017-04-01 10:00', 1, TRUE, 10, 1, 1, 1, 1, 'a'),
+ ('2017-05-01', '2017-05-01 10:00', 1, FALSE, 10, 1, 1, 1, 1, 'a'),
+ ('2017-06-01', '2017-06-01 10:00', 1, TRUE, 10, 1, 1, 1, 1, 'c'),
+ ('2017-07-01', '2017-07-01 10:00', 1, FALSE, 10, 1, 1, 1, 1, 'a'),
+ ('2017-08-01', '2017-08-01 10:00', 1, TRUE, 10, 1, 1, 1, 1, 'b');
diff --git a/tests/test_schema1.py b/tests/test_schema1.py
index 9d79d72..a7de3da 100644
--- a/tests/test_schema1.py
+++ b/tests/test_schema1.py
@@ -68,3 +68,18 @@ def test_boolean_dimension(schema1, app, admin):
form.set('filter__boolean', [o[0] for o in form.fields['filter__boolean'][0].options if o[2] == 'Oui'][0])
response = form.submit('visualize')
assert get_table(response) == [['Boolean', 'Oui'], ['number of rows', '8']]
+
+
+def test_string_dimension(schema1, app, admin):
+ login(app, admin)
+ response = app.get('/').follow()
+ response = response.click('Facts 1')
+ form = response.form
+ form.set('representation', 'table')
+ form.set('measure', 'simple_count')
+ form.set('drilldown_x', 'string')
+ response = form.submit('visualize')
+ assert get_table(response) == [['String', 'a', 'b', 'c', 'Aucun(e)'], ['number of rows', '11', '2', '3', '1']]
+ form.set('filter__string', ['a', 'b', '__none__'])
+ response = form.submit('visualize')
+ assert get_table(response) == [['String', 'a', 'b', 'Aucun(e)'], ['number of rows', '11', '2', '1']]