def benchmark_calculate_course_category_aggregate(student, course, category, marking_period, items=None): if items is None: items = Item.objects.all() save = True else: # don't store aggregates for every one-off combination of items save = False items = items.filter(course=course, category=category) # if we're passed marking_period=None, we should consider items across the entire duration of the course # if we're passed a specific marking period instead, we should consider items matching only that marking period if marking_period is not None: items = items.filter(marking_period=marking_period) calculation_rule = benchmark_find_calculation_rule(course.marking_period.all()[0].school_year) # initialize attributes criteria = {"course": course, "category": category, "marking_period": marking_period} # silly name is silly, and should not be part of the criteria silly_name = "G! {} - {} ({}, {})".format(student, category, course, marking_period) # don't use get_or_create; otherwise we may end up saving an empty object try: agg = benchmark_get_or_flush(student.aggregate_set, **criteria) created = False except Aggregate.DoesNotExist: agg = Aggregate(student=student, **criteria) created = True agg.name = silly_name # begin the actual calculations! agg.cached_substitution = None category_numer = category_denom = Decimal(0) if category.allow_multiple_demonstrations: for category_item in items.exclude(points_possible=None): # Find the highest mark amongst demonstrations and count it as the grade for the item best = Mark.objects.filter(student=student, item=category_item).aggregate(Max("mark"))["mark__max"] if best is not None: calculate_as, display_as = calculation_rule.substitute(category_item, best) category_numer += calculate_as category_denom += category_item.points_possible # yes, agg will just end up with the last substitution, but tough if display_as is not None: agg.cached_substitution = display_as else: for category_mark in ( Mark.objects.filter(student=student, item__in=items).exclude(mark=None).exclude(item__points_possible=None) ): calculate_as, display_as = calculation_rule.substitute(category_mark.item, category_mark.mark) category_numer += calculate_as category_denom += category_mark.item.points_possible if display_as is not None: agg.cached_substitution = display_as if category_denom: agg.cached_value = category_numer / category_denom * agg._fallback_points_possible() else: agg.cached_value = None if save: agg.save() return agg, created
def benchmark_calculate_course_category_aggregate(student, course_section, category, marking_period, items=None): if items is None: items = Item.objects.all() save = True else: # don't store aggregates for every one-off combination of items save = False items = items.filter(course_section=course_section, category=category) # if we're passed marking_period=None, we should consider items across the entire duration of the course section # if we're passed a specific marking period instead, we should consider items matching only that marking period if marking_period is not None: items = items.filter(marking_period=marking_period) calculation_rule = benchmark_find_calculation_rule( course_section.marking_period.all()[0].school_year) # initialize attributes criteria = { 'course_section': course_section, 'category': category, 'marking_period': marking_period } # silly name is silly, and should not be part of the criteria silly_name = 'G! {} - {} ({}, {})'.format(student, category, course_section, marking_period) # don't use get_or_create; otherwise we may end up saving an empty object try: agg = benchmark_get_or_flush(student.aggregate_set, **criteria) created = False except Aggregate.DoesNotExist: agg = Aggregate(student=student, **criteria) created = True agg.name = silly_name # begin the actual calculations! agg.cached_substitution = None category_numer = category_denom = Decimal(0) if category.allow_multiple_demonstrations: for category_item in items.exclude(points_possible=None): # Find the highest mark amongst demonstrations and count it as the grade for the item best = Mark.objects.filter(student=student, item=category_item).aggregate( Max('mark'))['mark__max'] if best is not None: calculate_as, display_as = calculation_rule.substitute( category_item, best) category_numer += calculate_as category_denom += category_item.points_possible # yes, agg will just end up with the last substitution, but tough if display_as is not None: agg.cached_substitution = display_as else: for category_mark in Mark.objects.filter( student=student, item__in=items).exclude(mark=None).exclude( item__points_possible=None): calculate_as, display_as = calculation_rule.substitute( category_mark.item, category_mark.mark) category_numer += calculate_as category_denom += category_mark.item.points_possible if display_as is not None: agg.cached_substitution = display_as if category_denom: agg.cached_value = category_numer / category_denom * agg._fallback_points_possible( ) else: agg.cached_value = None if save: agg.save() return agg, created