diff --git a/dashboard/static_src/scss/cards.scss b/dashboard/static_src/scss/cards.scss
index 0d203434..629a4211 100644
--- a/dashboard/static_src/scss/cards.scss
+++ b/dashboard/static_src/scss/cards.scss
@@ -17,22 +17,6 @@
}
}
-.card-averages {
- @extend .border-light;
-
- .card-header {
- @extend .text-dark, .bg-light;
- }
-
- .card-body {
- @extend .text-light;
-
- .container {
- padding: 0;
- }
- }
-}
-
.card-diaperchange {
@extend .border-danger;
@@ -69,6 +53,22 @@
}
}
+.card-statistics {
+ @extend .border-light;
+
+ .card-header {
+ @extend .text-dark, .bg-light;
+ }
+
+ .card-body {
+ @extend .text-light;
+
+ .container {
+ padding: 0;
+ }
+ }
+}
+
.card-timer {
@extend .border-light;
diff --git a/dashboard/templates/cards/averages.html b/dashboard/templates/cards/averages.html
deleted file mode 100644
index b64e77f7..00000000
--- a/dashboard/templates/cards/averages.html
+++ /dev/null
@@ -1,62 +0,0 @@
-{% load duration %}
-
-
-
-
-
-
-
-
Nap time
- {% if naps.average %}
- {{ naps.average|duration_string:'m' }}
- {% else %}
-
Not enough data
- {% endif %}
-
-
-
Naps/day
- {% if naps.avg_per_day %}
- {{ naps.avg_per_day|floatformat }}
- {% else %}
-
Not enough data
- {% endif %}
-
-
-
Sleep time
- {% if sleep.average %}
- {{ sleep.average|duration_string:'m' }}
- {% else %}
-
Not enough data
- {% endif %}
-
-
-
Awake time
- {% if sleep.btwn_average %}
- {{ sleep.btwn_average|duration_string:'m' }}
- {% else %}
-
Not enough data
- {% endif %}
-
-
-
Change freq.
- {% if changes.btwn_average %}
- {{ changes.btwn_average|duration_string:'m' }}
- {% else %}
-
Not enough data
- {% endif %}
-
-
-
Feeding freq.
- {% if feedings.btwn_average %}
- {{ feedings.btwn_average|duration_string:'m' }}
- {% else %}
-
Not enough data
- {% endif %}
-
-
-
-
-
\ No newline at end of file
diff --git a/dashboard/templates/cards/statistics.html b/dashboard/templates/cards/statistics.html
new file mode 100644
index 00000000..fd73ccfc
--- /dev/null
+++ b/dashboard/templates/cards/statistics.html
@@ -0,0 +1,40 @@
+{% load duration %}
+
+
+
+
+
+
+ {% for stat in stats %}
+
+
+ {% if stat.stat %}
+ {% if stat.type == 'duration' %}
+ {{ stat.stat|duration_string:'m' }}
+ {% elif stat.type == 'float' %}
+ {{ stat.stat|floatformat }}
+ {% else %}
+ {{ stat.stat }}
+ {% endif %}
+ {% else %}
+ Not enough data
+ {% endif %}
+
+
{{ stat.title }}
+
+ {% endfor %}
+
+
+
+ Previous
+
+
+
+ Next
+
+
+
+
\ No newline at end of file
diff --git a/dashboard/templates/dashboard/child.html b/dashboard/templates/dashboard/child.html
index 76459fab..779e712a 100644
--- a/dashboard/templates/dashboard/child.html
+++ b/dashboard/templates/dashboard/child.html
@@ -15,7 +15,7 @@
{% card_feeding_last object %}
{% card_feeding_last_method object %}
{% card_timer_list %}
- {% card_averages object %}
+ {% card_statistics object %}
{% card_sleep_last object %}
diff --git a/dashboard/templatetags/cards.py b/dashboard/templatetags/cards.py
index 451b53af..1cf1c0f8 100644
--- a/dashboard/templatetags/cards.py
+++ b/dashboard/templatetags/cards.py
@@ -12,121 +12,6 @@ from core.models import DiaperChange, Feeding, Sleep, Timer, TummyTime
register = template.Library()
-@register.inclusion_tag('cards/averages.html')
-def card_averages(child):
- """
- Averages data for all models.
- :param child: an instance of the Child model.
- :returns: a dictionary of Diaper Change, Feeding and Sleep averages data.
- """
- return {
- 'changes': _diaperchange_averages(child),
- 'feedings': _feeding_averages(child),
- 'naps': _nap_averages(child),
- 'sleep': _sleep_averages(child)}
-
-
-def _diaperchange_averages(child):
- """
- Averaged Diaper Change data.
- :param child: an instance of the Child model.
- :returns: a dictionary of Diaper Change averages data.
- """
- instances = DiaperChange.objects.filter(child=child).order_by('time')
- changes = {
- 'btwn_total': timezone.timedelta(0),
- 'btwn_count': instances.count() - 1,
- 'btwn_average': 0}
- last_instance = None
-
- for instance in instances:
- if last_instance:
- changes['btwn_total'] += instance.time - last_instance.time
- last_instance = instance
-
- if changes['btwn_count'] > 0:
- changes['btwn_average'] = changes['btwn_total'] / changes['btwn_count']
-
- return changes
-
-
-def _feeding_averages(child):
- """
- Averaged Feeding data.
- :param child: an instance of the Child model.
- :returns: a dictionary of Feeding averages data.
- """
- instances = Feeding.objects.filter(child=child).order_by('start')
- feedings = {
- 'btwn_total': timezone.timedelta(0),
- 'btwn_count': instances.count() - 1,
- 'btwn_average': 0}
- last_instance = None
-
- for instance in instances:
- if last_instance:
- feedings['btwn_total'] += instance.start - last_instance.end
- last_instance = instance
-
- if feedings['btwn_count'] > 0:
- feedings['btwn_average'] = \
- feedings['btwn_total'] / feedings['btwn_count']
-
- return feedings
-
-
-def _nap_averages(child):
- """
- Averaged nap data.
- :param child: an instance of the Child model.
- :returns: a dictionary of nap (Sleep) averages data.
- """
- instances = Sleep.naps.filter(child=child).order_by('start')
- naps = {
- 'total': instances.aggregate(Sum('duration'))['duration__sum'],
- 'count': instances.count(),
- 'average': 0,
- 'avg_per_day': 0}
- if naps['count'] > 0:
- naps['average'] = naps['total'] / naps['count']
-
- naps_avg = instances.annotate(date=TruncDate('start')).values('date') \
- .annotate(naps_count=Count('id')).order_by() \
- .aggregate(Avg('naps_count'))
- naps['avg_per_day'] = naps_avg['naps_count__avg']
-
- return naps
-
-
-def _sleep_averages(child):
- """
- Averaged Sleep data.
- :param child: an instance of the Child model.
- :returns: a dictionary of Sleep averages data.
- """
- instances = Sleep.objects.filter(child=child).order_by('start')
- sleep = {
- 'total': instances.aggregate(Sum('duration'))['duration__sum'],
- 'count': instances.count(),
- 'average': 0,
- 'btwn_total': timezone.timedelta(0),
- 'btwn_count': instances.count() - 1,
- 'btwn_average': 0}
-
- last_instance = None
- for instance in instances:
- if last_instance:
- sleep['btwn_total'] += instance.start - last_instance.end
- last_instance = instance
-
- if sleep['count'] > 0:
- sleep['average'] = sleep['total'] / sleep['count']
- if sleep['btwn_count'] > 0:
- sleep['btwn_average'] = sleep['btwn_total'] / sleep['btwn_count']
-
- return sleep
-
-
@register.inclusion_tag('cards/diaperchange_last.html')
def card_diaperchange_last(child):
"""
@@ -261,6 +146,151 @@ def card_sleep_naps_day(child, date=None):
'count': len(instances)}
+@register.inclusion_tag('cards/statistics.html')
+def card_statistics(child):
+ """
+ Statistics data for all models.
+ :param child: an instance of the Child model.
+ :returns: a list of dictionaries with "type", "stat" and "title" entries.
+ """
+ stats = []
+
+ changes = _diaperchange_averages(child)
+ stats.append({
+ 'type': 'duration',
+ 'stat': changes['btwn_average'],
+ 'title': 'Diaper change frequency'})
+
+ feedings = _feeding_averages(child)
+ stats.append({
+ 'type': 'duration',
+ 'stat': feedings['btwn_average'],
+ 'title': 'Feeding frequency'})
+
+ naps = _nap_averages(child)
+ stats.append({
+ 'type': 'duration',
+ 'stat': naps['average'],
+ 'title': 'Average nap duration'})
+ stats.append({
+ 'type': 'float',
+ 'stat': naps['avg_per_day'],
+ 'title': 'Average naps per day'})
+
+ sleep = _sleep_averages(child)
+ stats.append({
+ 'type': 'duration',
+ 'stat': sleep['average'],
+ 'title': 'Average sleep duration'})
+ stats.append({
+ 'type': 'duration',
+ 'stat': sleep['btwn_average'],
+ 'title': 'Average awake duration'})
+
+ return {'stats': stats}
+
+
+def _diaperchange_averages(child):
+ """
+ Averaged Diaper Change data.
+ :param child: an instance of the Child model.
+ :returns: a dictionary of Diaper Change averages data.
+ """
+ instances = DiaperChange.objects.filter(child=child).order_by('time')
+ changes = {
+ 'btwn_total': timezone.timedelta(0),
+ 'btwn_count': instances.count() - 1,
+ 'btwn_average': 0}
+ last_instance = None
+
+ for instance in instances:
+ if last_instance:
+ changes['btwn_total'] += instance.time - last_instance.time
+ last_instance = instance
+
+ if changes['btwn_count'] > 0:
+ changes['btwn_average'] = changes['btwn_total'] / changes['btwn_count']
+
+ return changes
+
+
+def _feeding_averages(child):
+ """
+ Averaged Feeding data.
+ :param child: an instance of the Child model.
+ :returns: a dictionary of Feeding averages data.
+ """
+ instances = Feeding.objects.filter(child=child).order_by('start')
+ feedings = {
+ 'btwn_total': timezone.timedelta(0),
+ 'btwn_count': instances.count() - 1,
+ 'btwn_average': 0}
+ last_instance = None
+
+ for instance in instances:
+ if last_instance:
+ feedings['btwn_total'] += instance.start - last_instance.end
+ last_instance = instance
+
+ if feedings['btwn_count'] > 0:
+ feedings['btwn_average'] = \
+ feedings['btwn_total'] / feedings['btwn_count']
+
+ return feedings
+
+
+def _nap_averages(child):
+ """
+ Averaged nap data.
+ :param child: an instance of the Child model.
+ :returns: a dictionary of nap (Sleep) averages data.
+ """
+ instances = Sleep.naps.filter(child=child).order_by('start')
+ naps = {
+ 'total': instances.aggregate(Sum('duration'))['duration__sum'],
+ 'count': instances.count(),
+ 'average': 0,
+ 'avg_per_day': 0}
+ if naps['count'] > 0:
+ naps['average'] = naps['total'] / naps['count']
+
+ naps_avg = instances.annotate(date=TruncDate('start')).values('date') \
+ .annotate(naps_count=Count('id')).order_by() \
+ .aggregate(Avg('naps_count'))
+ naps['avg_per_day'] = naps_avg['naps_count__avg']
+
+ return naps
+
+
+def _sleep_averages(child):
+ """
+ Averaged Sleep data.
+ :param child: an instance of the Child model.
+ :returns: a dictionary of Sleep averages data.
+ """
+ instances = Sleep.objects.filter(child=child).order_by('start')
+ sleep = {
+ 'total': instances.aggregate(Sum('duration'))['duration__sum'],
+ 'count': instances.count(),
+ 'average': 0,
+ 'btwn_total': timezone.timedelta(0),
+ 'btwn_count': instances.count() - 1,
+ 'btwn_average': 0}
+
+ last_instance = None
+ for instance in instances:
+ if last_instance:
+ sleep['btwn_total'] += instance.start - last_instance.end
+ last_instance = instance
+
+ if sleep['count'] > 0:
+ sleep['average'] = sleep['total'] / sleep['count']
+ if sleep['btwn_count'] > 0:
+ sleep['btwn_average'] = sleep['btwn_total'] / sleep['btwn_count']
+
+ return sleep
+
+
@register.inclusion_tag('cards/timer_list.html')
def card_timer_list():
"""