From d31b6efef49883be51c11c5106cc4876e5c76455 Mon Sep 17 00:00:00 2001 From: Mark Young Date: Mon, 23 Sep 2024 17:37:49 -0700 Subject: [PATCH 1/8] Added type hinting --- templatetags/high_health_helpers.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/templatetags/high_health_helpers.py b/templatetags/high_health_helpers.py index a89ca16..c62a5c2 100644 --- a/templatetags/high_health_helpers.py +++ b/templatetags/high_health_helpers.py @@ -1,4 +1,5 @@ import logging +from typing import Union from django import template from high_health.models import Measure @@ -10,7 +11,7 @@ @register.filter -def goal_format(measure): +def goal_format(measure: Measure) -> str: # This method creates a tag that determines the color of the text # Color codings found in css file if measure.metric.frequency == "MoM": @@ -32,7 +33,7 @@ def goal_format(measure): return yoy_color_eval(measure, previous_outcome) -def yoy_color_eval(measure, previous): +def yoy_color_eval(measure: Measure, previous: Union[int, None]) -> str: if measure.goal.goal_type.upper() == "ABOVE": if measure.value >= measure.goal.target: return "success" From 07367620fb7a97f24bf348a4883aa4026d1b3eb7 Mon Sep 17 00:00:00 2001 From: Mark Young Date: Mon, 23 Sep 2024 17:39:09 -0700 Subject: [PATCH 2/8] Set goal_distance template tag to handle None --- templatetags/high_health_helpers.py | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/templatetags/high_health_helpers.py b/templatetags/high_health_helpers.py index c62a5c2..da6e983 100644 --- a/templatetags/high_health_helpers.py +++ b/templatetags/high_health_helpers.py @@ -72,24 +72,27 @@ def mom_color_eval(measure, previous): @register.filter -def addstr(arg1, arg2): +def addstr(arg1: str, arg2: str) -> str: """concatenate arg1 & arg2""" return str(arg1) + str(arg2) @register.filter -def goal_distance(measure): - if measure.goal.goal_type == "ABOVE": - if measure.value < measure.goal.target: - return f"-{measure.goal.target - measure.value}% below goal" - else: - return f"+{measure.value - measure.goal.target}% above goal" +def goal_distance(measure: Measure) -> str: + if measure.goal is not None: + if measure.goal.goal_type == "ABOVE": + if measure.value < measure.goal.target: + return f"-{measure.goal.target - measure.value}% below goal" + else: + return f"+{measure.value - measure.goal.target}% above goal" - else: - if measure.value > measure.goal.target: - return f"+{measure.value - measure.goal.target}% above goal" else: - return f"-{measure.goal.target - measure.value}% below goal" + if measure.value > measure.goal.target: + return f"+{measure.value - measure.goal.target}% above goal" + else: + return f"-{measure.goal.target - measure.value}% below goal" + else: + return "No goal set for this metric." register.filter("goal_format", goal_format) From 8b208f1225193bfe1d9eb0f48e22753ec722045f Mon Sep 17 00:00:00 2001 From: Mark Young Date: Mon, 23 Sep 2024 17:39:45 -0700 Subject: [PATCH 3/8] Created get_mom_previous_outcome func --- templatetags/high_health_helpers.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/templatetags/high_health_helpers.py b/templatetags/high_health_helpers.py index da6e983..e480dc8 100644 --- a/templatetags/high_health_helpers.py +++ b/templatetags/high_health_helpers.py @@ -50,7 +50,21 @@ def yoy_color_eval(measure: Measure, previous: Union[int, None]) -> str: return "danger" -def mom_color_eval(measure, previous): +def get_mom_previous_outcome(measure: Measure) -> Union[int, None]: + current_month = measure.month + last_year = measure.year - 1 + try: + previous_outcome = Measure.objects.filter( + metric=measure.metric.id, + date__month=current_month, + date__year=last_year, + school=measure.school)[0].value + except IndexError: + previous_outcome = None + return previous_outcome + + +def mom_color_eval(measure, previous: Union[int, None]) -> str: # Filtering the % Staffed metric out of evaluation if measure.metric.id == 36: return "secondary" From 9f13d91a1b2534a8f1d0afbd6815efcd607c76d8 Mon Sep 17 00:00:00 2001 From: Mark Young Date: Mon, 23 Sep 2024 17:55:01 -0700 Subject: [PATCH 4/8] Updated goal_format template tag logic to handle None --- templatetags/high_health_helpers.py | 36 ++++++++++++++--------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/templatetags/high_health_helpers.py b/templatetags/high_health_helpers.py index e480dc8..efeef55 100644 --- a/templatetags/high_health_helpers.py +++ b/templatetags/high_health_helpers.py @@ -15,18 +15,7 @@ def goal_format(measure: Measure) -> str: # This method creates a tag that determines the color of the text # Color codings found in css file if measure.metric.frequency == "MoM": - current_month = measure.month - last_year = measure.year - 1 - try: - previous_outcome = Measure.objects.filter( - metric=measure.metric.id, - date__month=current_month, - date__year=last_year, - school=measure.school)[0].value - except IndexError: - previous_outcome = measure.goal.previous_outcome - if previous_outcome is None: - previous_outcome = measure.goal.previous_outcome + previous_outcome = get_mom_previous_outcome(measure) return mom_color_eval(measure, previous_outcome) else: previous_outcome = measure.goal.previous_outcome @@ -37,13 +26,17 @@ def yoy_color_eval(measure: Measure, previous: Union[int, None]) -> str: if measure.goal.goal_type.upper() == "ABOVE": if measure.value >= measure.goal.target: return "success" + elif previous is None: + return "secondary" elif measure.goal.target > measure.value >= previous: return "secondary" else: return "danger" - else: + elif measure.goal.goal_type.upper() != "ABOVE": if measure.value <= measure.goal.target: return "success" + elif previous is None: + return "secondary" elif measure.goal.target < measure.value <= previous: return "secondary" else: @@ -66,18 +59,25 @@ def get_mom_previous_outcome(measure: Measure) -> Union[int, None]: def mom_color_eval(measure, previous: Union[int, None]) -> str: # Filtering the % Staffed metric out of evaluation - if measure.metric.id == 36: - return "secondary" - if measure.goal.goal_type.upper() == "ABOVE": - if measure.value < previous: + if previous is None: + if measure.value >= measure.goal.target: + return "success" + else: + return "secondary" + elif measure.value < previous: return "danger" elif measure.value >= measure.goal.target and measure.value >= previous: return "success" else: return "secondary" else: - if measure.value > previous: + if previous is None: + if measure.value >= measure.goal.target: + return "success" + else: + return "secondary" + elif measure.value > previous: return "danger" elif measure.value <= measure.goal.target and measure.value <= previous: return "success" From 9c25c2473c1b6a2e7168bce993f403b97c803b9a Mon Sep 17 00:00:00 2001 From: Mark Young Date: Mon, 23 Sep 2024 20:44:13 -0700 Subject: [PATCH 5/8] Restructured HH views.py --- high_health/views.py | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/high_health/views.py b/high_health/views.py index 2c8e80a..d528df8 100644 --- a/high_health/views.py +++ b/high_health/views.py @@ -1,10 +1,12 @@ import logging import math +from typing import List from datetime import datetime from dateutil.relativedelta import relativedelta from itertools import chain, groupby from django.contrib.auth.models import Group from django.contrib.auth.decorators import login_required, user_passes_test +from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import PermissionDenied from django.db.models import Avg from django.http import JsonResponse @@ -30,6 +32,14 @@ DANGER_COLOR = "#E8605D" +def get_schools(school_level): + if school_level.name == "RS": + schools = Site.objects.filter(school_level=school_level).order_by("id") + else: + schools = Site.objects.filter(school_level=school_level) + return schools + + def last_updated(metric_id): try: return ( @@ -51,13 +61,19 @@ def metrics(school_level): .distinct() .order_by("id") ) + return metrics + + +def get_measures(hh_metrics, schools): data = [] - for metric in metrics: + for metric in hh_metrics: # Note: Summer 2024 - filtering out all HH reports except ADA, CA, and Suspensions # Temporarily commenting out metric 3 - chronic absence if metric.id in (2, 5): measures = metric.measure_set.filter(school__school_level=school_level, is_current=True).order_by(order_by) if measures: + if len(measures) != len(schools): + measures = fill_missing_measures(measures, schools) metric_data = { "metric": metric, "last_updated": last_updated(metric.id), @@ -67,6 +83,12 @@ def metrics(school_level): return sorted(data, key=lambda d: d["last_updated"], reverse=True) +def fill_missing_measures(measures, schools: List[Site]): + missing_indexes = set([index for index, measure in enumerate(measures) if measure.school not in schools]) + filled_list = [measure if index not in missing_indexes else None for index, measure in enumerate(measures)] + return filled_list + + def last_value(values): if values: return values[-1] @@ -317,14 +339,15 @@ def chart_data(request, metric_id, school_id): def high_health(request, school_level=None): # TODO: Convert to query school level by name instead of id school_level = SchoolLevel.objects.get(pk=school_level) - if school_level.name == "RS": - schools = Site.objects.filter(school_level=school_level).order_by("id") - else: - schools = Site.objects.filter(school_level=school_level) + + schools = get_schools(school_level) + school_metrics = get_metrics(school_level) + metrics_and_measures = get_measures(school_metrics, schools) + context = { "school_level": school_level, "schools": schools, - "metrics": metrics(school_level), + "metrics": metrics_and_measures, "school_levels": SchoolLevel.objects.all(), } return render(request, "high_health.html", context) From 3c7a5550f0bf01f443d71cd32b96458d52207ad7 Mon Sep 17 00:00:00 2001 From: Mark Young Date: Mon, 23 Sep 2024 20:44:34 -0700 Subject: [PATCH 6/8] Updated HH html --- templates/high_health.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/templates/high_health.html b/templates/high_health.html index 299dcc5..db9bcc8 100644 --- a/templates/high_health.html +++ b/templates/high_health.html @@ -63,11 +63,11 @@

High Health: {{ school_level.display_name }}

{% for measure in metric.measures %} - {% if measure.value is None %} - - - N/A - + {% if measure is None or measure.value is None %} + + + N/A + {% else %} Date: Thu, 26 Sep 2024 14:23:12 -0700 Subject: [PATCH 7/8] Filtering out Stockton HS; Bringing back Chron Ab --- high_health/views.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/high_health/views.py b/high_health/views.py index 2c8e80a..3b16792 100644 --- a/high_health/views.py +++ b/high_health/views.py @@ -54,8 +54,7 @@ def metrics(school_level): data = [] for metric in metrics: # Note: Summer 2024 - filtering out all HH reports except ADA, CA, and Suspensions - # Temporarily commenting out metric 3 - chronic absence - if metric.id in (2, 5): + if metric.id in (2, 3, 5): measures = metric.measure_set.filter(school__school_level=school_level, is_current=True).order_by(order_by) if measures: metric_data = { @@ -320,7 +319,8 @@ def high_health(request, school_level=None): if school_level.name == "RS": schools = Site.objects.filter(school_level=school_level).order_by("id") else: - schools = Site.objects.filter(school_level=school_level) + # Filtering out Stockton HS + schools = Site.objects.filter(school_level=school_level).exclude(id=36) context = { "school_level": school_level, "schools": schools, From 9591fbfb9d29d08ccae132b4e9dbfb5776f2ca48 Mon Sep 17 00:00:00 2001 From: Mark Young Date: Thu, 26 Sep 2024 14:34:28 -0700 Subject: [PATCH 8/8] Reverted changes to HH views again --- high_health/views.py | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/high_health/views.py b/high_health/views.py index f5ec0ee..bb384c7 100644 --- a/high_health/views.py +++ b/high_health/views.py @@ -32,14 +32,6 @@ DANGER_COLOR = "#E8605D" -def get_schools(school_level): - if school_level.name == "RS": - schools = Site.objects.filter(school_level=school_level).order_by("id") - else: - schools = Site.objects.filter(school_level=school_level) - return schools - - def last_updated(metric_id): try: return ( @@ -61,18 +53,12 @@ def metrics(school_level): .distinct() .order_by("id") ) - return metrics - - -def get_measures(hh_metrics, schools): data = [] - for metric in hh_metrics: + for metric in metrics: # Note: Summer 2024 - filtering out all HH reports except ADA, CA, and Suspensions if metric.id in (2, 3, 5): measures = metric.measure_set.filter(school__school_level=school_level, is_current=True).order_by(order_by) if measures: - if len(measures) != len(schools): - measures = fill_missing_measures(measures, schools) metric_data = { "metric": metric, "last_updated": last_updated(metric.id), @@ -346,7 +332,7 @@ def high_health(request, school_level=None): context = { "school_level": school_level, "schools": schools, - "metrics": metrics_and_measures, + "metrics": metrics(school_level), "school_levels": SchoolLevel.objects.all(), } return render(request, "high_health.html", context)