created MultipleChartsView

This commit is contained in:
artus40
2017-08-18 14:00:59 +02:00
parent c8c59b92a2
commit 6d2ce7d7bc
6 changed files with 189 additions and 103 deletions

View File

@@ -1,61 +1,88 @@
from django.db.models import (Field, CharField, NullBooleanField,
from django.db.models import (Field, NullBooleanField,
Count,
)
from graphos.sources.simple import SimpleDataSource
from graphos.renderers import gchart
# Defines generic labels for common fields
LABELS = {
NullBooleanField: {True: "Oui", False: "Non", None:"Ne sait pas"},
}
class FieldValuesCountDataSource(SimpleDataSource):
""" Generates data from a limited set of choices.
"""
def __init__(self, queryset, field, labels=None, excluded=[]):
self.queryset = queryset
self.field_name = field.name
self.excluded = excluded
if not labels:
if field.__class__ in LABELS:
labels = LABELS[field.__class__]
elif field.choices:
labels = dict(field.choices)
else:
raise ValueError("Could not retrieve labels for", field)
self.labels = labels
super().__init__(self.create_data())
def create_data(self):
data = [(self.field_name, "%s_count" % self.field_name)] # Headers
data += [
(self.labels[item[self.field_name]], # Display a label instead of raw values
item['count']
) for item in self.queryset.values( # Retrieve all values for field
self.field_name
).annotate( # Count occurrences of each value
count=Count('pk')
).order_by() # Needed so that counts are aggregated
# Exclude values that are marked to be ignored
if (not self.excluded
or item[self.field_name] not in self.excluded)
]
return data
class PieWrapper(gchart.PieChart):
""" A wrapper around gchart.PieChart that generates a graph from :
- a queryset and a model field (NullBooleanField or field with choices)
OR
- a data object and title
"""
height=400
width=800
labels = {
NullBooleanField: {True: "Oui", False: "Non", None:"Ne sait pas"},
}
def __init__( self, queryset=None, field=None,
data=None, title=None,
null_values=[],**kwargs):
def __init__(self,
queryset=None, field=None,
data=None, title=None,
null_values=[],
**kwargs):
if not data:
if not isinstance(field, Field):
raise TypeError(field, 'must be a child of django.models.db.fields.Field !')
if not queryset:
raise TypeError("You must give either a queryset and field or data")
if field.__class__ in PieWrapper.labels:
labels = PieWrapper.labels[field.__class__]
elif field.choices:
labels = dict(field.choices)
else:
raise ValueError("Could not guess labels for", field)
data = ([(field.name, 'count')] + # Headers
[(labels[item[field.name]],
item['nbr']) for item in queryset.values(
field.name
).annotate(
nbr=Count('pk')
).order_by()
if (not null_values
or item[field] not in null_values)
])
data_source = FieldValuesCountDataSource(
queryset, field,
excluded=null_values,
labels=None #TODO: How to pass in labels ??
)
else:
data_source = SimpleDataSource(data=data)
super().__init__(
SimpleDataSource(
data=data
),
data_source,
options={
'title': getattr(field, 'verbose_name', title),
'is3D': True,
'pieSliceText': 'value',
'legend': {'position': 'labeled', 'maxLines': 3, 'textStyle': {'fontSize': 16,}},
},
width=kwargs.get('width', self.width), height=kwargs.get('height', self.height),
width=kwargs.get('width', self.width),
height=kwargs.get('height', self.height),
)
def get_js_template(self):