def get_user_queryset(request, facility, group_id): """Return set of users appropriate to the facility and group""" student_ordering = ["last_name", "first_name", "username"] (groups, facilities, ungrouped_available) = get_accessible_objects_from_logged_in_user(request, facility=facility) if group_id: # Narrow by group users = FacilityUser.objects.filter( group=group_id, is_teacher=False).order_by(*student_ordering) # Narrow all by ungroup user if group_id == control_panel_api_resources.UNGROUPED_KEY: users = FacilityUser.objects.filter(group__isnull=True, is_teacher=False).order_by(*student_ordering) if facility: users = FacilityUser.objects.filter(facility=facility, group__isnull=True, is_teacher=False).order_by(*student_ordering) elif facility: # Narrow by facility search_groups = [groups_dict["groups"] for groups_dict in groups if groups_dict["facility"] == facility.id] assert len(search_groups) <= 1, "Should only have one or zero matches." # Return groups and ungrouped search_groups = search_groups[0] # make sure to include ungrouped students users = FacilityUser.objects.filter( Q(group__in=search_groups) | Q(group=None, facility=facility), is_teacher=False).order_by(*student_ordering) else: # Show all (including ungrouped) search_groups = [] for groups_dict in groups: search_groups += groups_dict["groups"] users = FacilityUser.objects.filter( Q(group__in=search_groups) | Q(group=None), is_teacher=False).order_by(*student_ordering) return users
def plotting_metadata_context(request, facility=None, topic_path=[], *args, **kwargs): """Basic context for any plot: get the data form, a dictionary of stat definitions, and the full gamut of facility/group objects relevant to the request.""" # Get the form, and retrieve the API data form = get_data_form(request, facility=facility, topic_path=topic_path, *args, **kwargs) (groups, facilities, ungrouped_available) = get_accessible_objects_from_logged_in_user( request, facility=facility) return { "form": form.data, "stats": stats_dict, "groups": groups, "facilities": facilities, "ungrouped_available": ungrouped_available, }
def obj_get_list(self, bundle, **kwargs): """ Default options will be "All" groups and if a facility has ungrouped students, also add an "Ungrouped" option. Then we add the list of facilities after the above default options. Must return no groups if there are no groups for the user. """ # Call with facility=None argument to get all facilities and to determine if has ungrouped students. (groups, facilities, ungrouped_available) = get_accessible_objects_from_logged_in_user( bundle.request, facility=None) # Filter records only for all facilities accessible for the user qs = [] if facilities: facility_ids = facilities.values_list("id", flat=True) # Get the facility requested by client, if there is any, and validate it # from the list of facilities for the user. facility_id = bundle.request.GET.get('facility_id') if facility_id and facility_id != ID_NONE: if facility_id in facility_ids: facility = Facility.objects.get(id=facility_id) ungrouped_available = facility.has_ungrouped_students qs = FacilityGroup.objects.filter(facility__id=facility_id) else: raise BadRequest( "No facility found with that facility_id.") else: qs = FacilityGroup.objects.filter( facility__id__in=facility_ids) # Flag to return only the FacilityGroup objects and not including the "All" and "Ungrouped" options. # TODO(cpauya): how to convert this into a kwargs above instead of a request.GET? groups_only = bundle.request.GET.get("groups_only", True) if groups_only: group_list = list(qs) else: default_list = [] if qs or ungrouped_available: # add the "All" option default_list = [FacilityGroup(id=ALL_KEY, name=_("All"))] # add the "Ungrouped" option if ungrouped_available: fg = FacilityGroup(id=UNGROUPED_KEY, name=_("Ungrouped")) default_list.append(fg) # add all the facility group options for the user group_list = default_list + list(qs) # call super to trigger auth return super(FacilityGroupResource, self).authorized_read_list(group_list, bundle)
def obj_get_list(self, bundle, **kwargs): """ Default options will be "All" groups and if a facility has ungrouped students, also add an "Ungrouped" option. Then we add the list of facilities after the above default options. Must return no groups if there are no groups for the user. """ # Call with facility=None argument to get all facilities and to determine if has ungrouped students. (groups, facilities, ungrouped_available) = get_accessible_objects_from_logged_in_user(bundle.request, facility=None) # Filter records only for all facilities accessible for the user qs = [] if facilities: facility_ids = facilities.values_list("id", flat=True) # Get the facility requested by client, if there is any, and validate it # from the list of facilities for the user. facility_id = bundle.request.GET.get('facility_id') if facility_id and facility_id != ID_NONE: if facility_id in facility_ids: facility = Facility.objects.get(id=facility_id) ungrouped_available = facility.has_ungrouped_students qs = FacilityGroup.objects.filter(facility__id=facility_id) else: raise BadRequest("No facility found with that facility_id.") else: qs = FacilityGroup.objects.filter(facility__id__in=facility_ids) # Flag to return only the FacilityGroup objects and not including the "All" and "Ungrouped" options. # TODO(cpauya): how to convert this into a kwargs above instead of a request.GET? groups_only = bundle.request.GET.get("groups_only", True) if groups_only: group_list = list(qs) else: default_list = [] if qs or ungrouped_available: # add the "All" option default_list = [FacilityGroup(id=ALL_KEY, name=_("All"))] # add the "Ungrouped" option if ungrouped_available: fg = FacilityGroup(id=UNGROUPED_KEY, name=_("Ungrouped")) default_list.append(fg) # add all the facility group options for the user group_list = default_list + list(qs) # call super to trigger auth return super(FacilityGroupResource, self).authorized_read_list(group_list, bundle)
def plotting_metadata_context(request, facility=None, topic_path=[], *args, **kwargs): """Basic context for any plot: get the data form, a dictionary of stat definitions, and the full gamut of facility/group objects relevant to the request.""" # Get the form, and retrieve the API data form = get_data_form(request, facility=facility, topic_path=topic_path, *args, **kwargs) (groups, facilities, ungrouped_available) = get_accessible_objects_from_logged_in_user(request, facility=facility) return { "form": form.data, "stats": stats_dict, "groups": groups, "facilities": facilities, "ungrouped_available": ungrouped_available, }
def get_user_queryset(request, facility, group_id): """Return set of users appropriate to the facility and group""" student_ordering = ["last_name", "first_name", "username"] (groups, facilities, ungrouped_available) = get_accessible_objects_from_logged_in_user( request, facility=facility) if group_id: # Narrow by group users = FacilityUser.objects.filter( group=group_id, is_teacher=False).order_by(*student_ordering) # Narrow all by ungroup user if group_id == control_panel_api_resources.UNGROUPED_KEY: users = FacilityUser.objects.filter( group__isnull=True, is_teacher=False).order_by(*student_ordering) if facility: users = FacilityUser.objects.filter( facility=facility, group__isnull=True, is_teacher=False).order_by(*student_ordering) elif facility: # Narrow by facility search_groups = [ groups_dict["groups"] for groups_dict in groups if groups_dict["facility"] == facility.id ] assert len(search_groups) <= 1, "Should only have one or zero matches." # Return groups and ungrouped search_groups = search_groups[ 0] # make sure to include ungrouped students users = FacilityUser.objects.filter( Q(group__in=search_groups) | Q(group=None, facility=facility), is_teacher=False).order_by(*student_ordering) else: # Show all (including ungrouped) search_groups = [] for groups_dict in groups: search_groups += groups_dict["groups"] users = FacilityUser.objects.filter( Q(group__in=search_groups) | Q(group=None), is_teacher=False).order_by(*student_ordering) return users
def test_view(request): """Test view gets data server-side and displays exam results""" facility, group_id, context = coach_nav_context(request, "test") # Get students users = get_user_queryset(request, facility, group_id) # Get the TestLog objects generated by this group of students # TODO(cpauya): what about queryset for ungrouped students? test_logs = None if group_id: test_logs = TestLog.objects.filter(user__group=group_id) # Narrow all by ungroup facility user if group_id == control_panel_api_resources.UNGROUPED_KEY: test_logs = TestLog.objects.filter(user__group__isnull=True) if facility: TestLog.objects.filter(user__facility=facility, user__group__isnull=True) else: TestLog.objects.filter(user__group__isnull=True) elif facility: test_logs = TestLog.objects.filter(user__facility=facility) else: # filter by all facilities and groups for the user (groups, facilities, ungrouped_available) = get_accessible_objects_from_logged_in_user(request, facility=facility) if facilities: facility_ids = facilities.values_list("id", flat=True) test_logs = TestLog.objects.filter(user__facility__id__in=facility_ids) # Get list of all test objects test_resource = TestResource() tests_list = test_resource._read_tests() # Get completed test objects (used as columns) completed_test_ids = set([item.test for item in test_logs]) test_objects = [test for test in tests_list if test.test_id in completed_test_ids] # Create the table results_table = OrderedDict() for s in users: s.name = s.get_name() user_test_logs = [log for log in test_logs if log.user == s] results_table[s] = [] for t in test_objects: log_object = next((log for log in user_test_logs if log.test == t.test_id), '') # The template expects a status and a score to display if log_object: test_object = log_object.get_test_object() score = round(100 * float(log_object.total_correct) / float(test_object.total_questions), 1) display_score = "%(score)d%% (%(correct)d/%(total_questions)d)" % {'score': score, 'correct': log_object.total_correct, 'total_questions': test_object.total_questions} if log_object.complete: # Case: completed => we show % score if score >= 80: status = _("pass") elif score >= 60: status = _("borderline") else: status = _("fail" ) results_table[s].append({ "status": status, "cell_display": display_score, "title": status.title(), }) else: # Case: has started, but has not finished => we display % score & # remaining in title n_remaining = test_object.total_questions - log_object.index status = _("incomplete") results_table[s].append({ "status": status, "cell_display": display_score, "title": status.title() + ": " + ungettext("%(n_remaining)d problem remaining", n_remaining) % {'n_remaining': n_remaining}, }) else: # Case: has not started status = _("not started") results_table[s].append({ "status": status, "cell_display": "", "title": status.title(), }) # This retrieves stats for students score_list = [round(100 * float(result.total_correct) / float(result.get_test_object().total_questions), 1) for result in user_test_logs] for stat in SUMMARY_STATS: if score_list: results_table[s].append({ "status": "statistic", "cell_display": "%d%%" % return_list_stat(score_list, stat), }) else: results_table[s].append({ "status": "statistic", "cell_display": "", }) # This retrieves stats for tests stats_dict = OrderedDict() for stat in SUMMARY_STATS: stats_dict[stat] = [] for test_obj in test_objects: # get the logs for this test across all users and then add summary stats log_scores = [round(100 * float(test_log.total_correct) / float(test_log.get_test_object().total_questions), 1) for test_log in test_logs if test_log.test == test_obj.test_id] stats_dict[stat].append("%d%%" % return_list_stat(log_scores, stat)) context.update(plotting_metadata_context(request, facility=facility)) context.update({ "results_table": results_table, "test_columns": test_objects, "summary_stats": SUMMARY_STATS, "stats_dict": stats_dict, }) return context
def tabular_view(request, report_type="exercise"): """Tabular view also gets data server-side.""" # important for setting the defaults for the coach nav bar language = lcode_to_django_lang(request.language) facility, group_id, context = coach_nav_context(request, "tabular") # Define how students are ordered--used to be as efficient as possible. student_ordering = ["last_name", "first_name", "username"] # Get a list of topics (sorted) and groups topics = [get_node_cache("Topic", language=language).get(tid["id"]) for tid in get_knowledgemap_topics(language=language) if report_type.title() in tid["contains"]] playlists = Playlist.all() (groups, facilities, ungrouped_available) = get_accessible_objects_from_logged_in_user(request, facility=facility) context.update(plotting_metadata_context(request, facility=facility)) context.update({ # For translators: the following two translations are nouns "report_types": ({"value": "exercise", "name":_("exercise")}, {"value": "video", "name": _("video")}), "request_report_type": report_type, "topics": [{"id": t["id"], "title": t["title"]} for t in topics if t], "playlists": [{"id": p.id, "title": p.title, "tag": p.tag} for p in playlists if p], }) # get querystring info topic_id = request.GET.get("topic", "") playlist_id = request.GET.get("playlist", "") # No valid data; just show generic # Exactly one of topic_id or playlist_id should be present if not ((topic_id or playlist_id) and not (topic_id and playlist_id)): if playlists: messages.add_message(request, WARNING, _("Please select a playlist.")) elif topics: messages.add_message(request, WARNING, _("Please select a topic.")) return context playlist = (filter(lambda p: p.id == playlist_id, Playlist.all()) or [None])[0] if group_id: # Narrow by group if group_id == control_panel_api_resources.UNGROUPED_KEY: users = FacilityUser.objects.filter(group__isnull=True, is_teacher=False) if facility: # filter only those ungrouped students for the facility users = users.filter(facility=facility) users = users.order_by(*student_ordering) else: # filter all ungroup students users = FacilityUser.objects.filter(group__isnull=True, is_teacher=False).order_by(*student_ordering) else: users = FacilityUser.objects.filter( group=group_id, is_teacher=False).order_by(*student_ordering) elif facility: # Narrow by facility search_groups = [groups_dict["groups"] for groups_dict in groups if groups_dict["facility"] == facility.id] assert len(search_groups) <= 1, "Should only have one or zero matches." # Return groups and ungrouped search_groups = search_groups[0] # make sure to include ungrouped students users = FacilityUser.objects.filter( Q(group__in=search_groups) | Q(group=None, facility=facility), is_teacher=False).order_by(*student_ordering) else: # Show all (including ungrouped) search_groups = [] for groups_dict in groups: search_groups += groups_dict["groups"] users = FacilityUser.objects.filter( Q(group__in=search_groups) | Q(group=None), is_teacher=False).order_by(*student_ordering) # We have enough data to render over a group of students # Get type-specific information if report_type == "exercise": # Fill in exercises if topic_id: exercises = get_topic_exercises(topic_id=topic_id) elif playlist: exercises = playlist.get_playlist_entries("Exercise", language=language) context["exercises"] = exercises # More code, but much faster exercise_names = [ex["id"] for ex in context["exercises"]] # Get students context["students"] = [] exlogs = ExerciseLog.objects \ .filter(user__in=users, exercise_id__in=exercise_names) \ .order_by(*["user__%s" % field for field in student_ordering]) \ .values("user__id", "struggling", "complete", "exercise_id") exlogs = list(exlogs) # force the query to be evaluated exlog_idx = 0 for user in users: log_table = {} while exlog_idx < len(exlogs) and exlogs[exlog_idx]["user__id"] == user.id: log_table[exlogs[exlog_idx]["exercise_id"]] = exlogs[exlog_idx] exlog_idx += 1 context["students"].append({ # this could be DRYer "first_name": user.first_name, "last_name": user.last_name, "username": user.username, "name": user.get_name(), "id": user.id, "exercise_logs": log_table, }) elif report_type == "video": # Fill in videos if topic_id: context["videos"] = get_topic_videos(topic_id=topic_id) elif playlist: context["videos"] = playlist.get_playlist_entries("Video", language=language) # More code, but much faster video_ids = [vid["id"] for vid in context["videos"]] # Get students context["students"] = [] vidlogs = VideoLog.objects \ .filter(user__in=users, video_id__in=video_ids) \ .order_by(*["user__%s" % field for field in student_ordering])\ .values("user__id", "complete", "video_id", "total_seconds_watched", "points") vidlogs = list(vidlogs) # force the query to be executed now vidlog_idx = 0 for user in users: log_table = {} while vidlog_idx < len(vidlogs) and vidlogs[vidlog_idx]["user__id"] == user.id: log_table[vidlogs[vidlog_idx]["video_id"]] = vidlogs[vidlog_idx] vidlog_idx += 1 context["students"].append({ # this could be DRYer "first_name": user.first_name, "last_name": user.last_name, "username": user.username, "name": user.get_name(), "id": user.id, "video_logs": log_table, }) else: raise Http404(_("Unknown report_type: %(report_type)s") % {"report_type": report_type}) # Validate results by showing user messages. if not users: # 1. check group facility groups if len(groups) > 0 and not groups[0]['groups']: # 1. No groups available (for facility) and "no students" returned. messages.add_message(request, WARNING, _("No learner accounts have been created for selected facility/group.")) elif topic_id and playlist_id: # 2. Both topic and playlist are selected. messages.add_message(request, WARNING, _("Please select either a topic or a playlist above, but not both.")) elif not topic_id and not playlist_id: # 3. Group was selected, but data not queried because a topic or playlist was not selected. if playlists: # 4. No playlist was selected. messages.add_message(request, WARNING, _("Please select a playlist.")) elif topics: # 5. No topic was selected. messages.add_message(request, WARNING, _("Please select a topic.")) else: # 6. Everything specified, but no users fit the query. messages.add_message(request, WARNING, _("No learner accounts in this group have been created.")) # End: Validate results by showing user messages. log_coach_report_view(request) return context
def test_view(request): """Test view gets data server-side and displays exam results""" facility, group_id, context = coach_nav_context(request, "test") # Get students users = get_user_queryset(request, facility, group_id) # Get the TestLog objects generated by this group of students # TODO(cpauya): what about queryset for ungrouped students? test_logs = None if group_id: test_logs = TestLog.objects.filter(user__group=group_id) # Narrow all by ungroup facility user if group_id == control_panel_api_resources.UNGROUPED_KEY: test_logs = TestLog.objects.filter(user__group__isnull=True) if facility: TestLog.objects.filter(user__facility=facility, user__group__isnull=True) else: TestLog.objects.filter(user__group__isnull=True) elif facility: test_logs = TestLog.objects.filter(user__facility=facility) else: # filter by all facilities and groups for the user (groups, facilities, ungrouped_available) = get_accessible_objects_from_logged_in_user( request, facility=facility) if facilities: facility_ids = facilities.values_list("id", flat=True) test_logs = TestLog.objects.filter( user__facility__id__in=facility_ids) # Get list of all test objects test_resource = TestResource() tests_list = test_resource._read_tests() # Get completed test objects (used as columns) completed_test_ids = set([item.test for item in test_logs]) test_objects = [ test for test in tests_list if test.test_id in completed_test_ids ] # Create the table results_table = OrderedDict() for s in users: s.name = s.get_name() user_test_logs = [log for log in test_logs if log.user == s] results_table[s] = [] for t in test_objects: log_object = next( (log for log in user_test_logs if log.test == t.test_id), '') # The template expects a status and a score to display if log_object: test_object = log_object.get_test_object() score = round( 100 * float(log_object.total_correct) / float(test_object.total_questions), 1) display_score = "%(score)d%% (%(correct)d/%(total_questions)d)" % { 'score': score, 'correct': log_object.total_correct, 'total_questions': test_object.total_questions } if log_object.complete: # Case: completed => we show % score if score >= 80: status = _("pass") elif score >= 60: status = _("borderline") else: status = _("fail") results_table[s].append({ "status": status, "cell_display": display_score, "title": status.title(), }) else: # Case: has started, but has not finished => we display % score & # remaining in title n_remaining = test_object.total_questions - log_object.index status = _("incomplete") results_table[s].append({ "status": status, "cell_display": display_score, "title": status.title() + ": " + ungettext("%(n_remaining)d problem remaining", n_remaining) % { 'n_remaining': n_remaining }, }) else: # Case: has not started status = _("not started") results_table[s].append({ "status": status, "cell_display": "", "title": status.title(), }) # This retrieves stats for students score_list = [ round( 100 * float(result.total_correct) / float(result.get_test_object().total_questions), 1) for result in user_test_logs ] for stat in SUMMARY_STATS: if score_list: results_table[s].append({ "status": "statistic", "cell_display": "%d%%" % return_list_stat(score_list, stat), }) else: results_table[s].append({ "status": "statistic", "cell_display": "", }) # This retrieves stats for tests stats_dict = OrderedDict() for stat in SUMMARY_STATS: stats_dict[stat] = [] for test_obj in test_objects: # get the logs for this test across all users and then add summary stats log_scores = [ round( 100 * float(test_log.total_correct) / float(test_log.get_test_object().total_questions), 1) for test_log in test_logs if test_log.test == test_obj.test_id ] stats_dict[stat].append("%d%%" % return_list_stat(log_scores, stat)) context.update(plotting_metadata_context(request, facility=facility)) context.update({ "results_table": results_table, "test_columns": test_objects, "summary_stats": SUMMARY_STATS, "stats_dict": stats_dict, }) return context
def tabular_view(request, report_type="exercise"): """Tabular view also gets data server-side.""" # important for setting the defaults for the coach nav bar language = lcode_to_django_lang(request.language) facility, group_id, context = coach_nav_context(request, "tabular") # Define how students are ordered--used to be as efficient as possible. student_ordering = ["last_name", "first_name", "username"] # Get a list of topics (sorted) and groups topics = [ get_node_cache("Topic", language=language).get(tid["id"]) for tid in get_knowledgemap_topics(language=language) if report_type.title() in tid["contains"] ] playlists = Playlist.all() (groups, facilities, ungrouped_available) = get_accessible_objects_from_logged_in_user( request, facility=facility) context.update(plotting_metadata_context(request, facility=facility)) context.update({ # For translators: the following two translations are nouns "report_types": ({ "value": "exercise", "name": _("exercise") }, { "value": "video", "name": _("video") }), "request_report_type": report_type, "topics": [{ "id": t["id"], "title": t["title"] } for t in topics if t], "playlists": [{ "id": p.id, "title": p.title, "tag": p.tag } for p in playlists if p], }) # get querystring info topic_id = request.GET.get("topic", "") playlist_id = request.GET.get("playlist", "") # No valid data; just show generic # Exactly one of topic_id or playlist_id should be present if not ((topic_id or playlist_id) and not (topic_id and playlist_id)): if playlists: messages.add_message(request, WARNING, _("Please select a playlist.")) elif topics: messages.add_message(request, WARNING, _("Please select a topic.")) return context playlist = (filter(lambda p: p.id == playlist_id, Playlist.all()) or [None])[0] if group_id: # Narrow by group if group_id == control_panel_api_resources.UNGROUPED_KEY: users = FacilityUser.objects.filter(group__isnull=True, is_teacher=False) if facility: # filter only those ungrouped students for the facility users = users.filter(facility=facility) users = users.order_by(*student_ordering) else: # filter all ungroup students users = FacilityUser.objects.filter( group__isnull=True, is_teacher=False).order_by(*student_ordering) else: users = FacilityUser.objects.filter( group=group_id, is_teacher=False).order_by(*student_ordering) elif facility: # Narrow by facility search_groups = [ groups_dict["groups"] for groups_dict in groups if groups_dict["facility"] == facility.id ] assert len(search_groups) <= 1, "Should only have one or zero matches." # Return groups and ungrouped search_groups = search_groups[ 0] # make sure to include ungrouped students users = FacilityUser.objects.filter( Q(group__in=search_groups) | Q(group=None, facility=facility), is_teacher=False).order_by(*student_ordering) else: # Show all (including ungrouped) search_groups = [] for groups_dict in groups: search_groups += groups_dict["groups"] users = FacilityUser.objects.filter( Q(group__in=search_groups) | Q(group=None), is_teacher=False).order_by(*student_ordering) # We have enough data to render over a group of students # Get type-specific information if report_type == "exercise": # Fill in exercises if topic_id: exercises = get_topic_exercises(topic_id=topic_id) elif playlist: exercises = playlist.get_playlist_entries("Exercise", language=language) context["exercises"] = exercises # More code, but much faster exercise_names = [ex["id"] for ex in context["exercises"]] # Get students context["students"] = [] exlogs = ExerciseLog.objects \ .filter(user__in=users, exercise_id__in=exercise_names) \ .order_by(*["user__%s" % field for field in student_ordering]) \ .values("user__id", "struggling", "complete", "exercise_id") exlogs = list(exlogs) # force the query to be evaluated exlog_idx = 0 for user in users: log_table = {} while exlog_idx < len( exlogs) and exlogs[exlog_idx]["user__id"] == user.id: log_table[exlogs[exlog_idx]["exercise_id"]] = exlogs[exlog_idx] exlog_idx += 1 context["students"].append({ # this could be DRYer "first_name": user.first_name, "last_name": user.last_name, "username": user.username, "name": user.get_name(), "id": user.id, "exercise_logs": log_table, }) elif report_type == "video": # Fill in videos if topic_id: context["videos"] = get_topic_videos(topic_id=topic_id) elif playlist: context["videos"] = playlist.get_playlist_entries( "Video", language=language) # More code, but much faster video_ids = [vid["id"] for vid in context["videos"]] # Get students context["students"] = [] vidlogs = VideoLog.objects \ .filter(user__in=users, video_id__in=video_ids) \ .order_by(*["user__%s" % field for field in student_ordering])\ .values("user__id", "complete", "video_id", "total_seconds_watched", "points") vidlogs = list(vidlogs) # force the query to be executed now vidlog_idx = 0 for user in users: log_table = {} while vidlog_idx < len( vidlogs) and vidlogs[vidlog_idx]["user__id"] == user.id: log_table[vidlogs[vidlog_idx] ["video_id"]] = vidlogs[vidlog_idx] vidlog_idx += 1 context["students"].append({ # this could be DRYer "first_name": user.first_name, "last_name": user.last_name, "username": user.username, "name": user.get_name(), "id": user.id, "video_logs": log_table, }) else: raise Http404( _("Unknown report_type: %(report_type)s") % {"report_type": report_type}) # Validate results by showing user messages. if not users: # 1. check group facility groups if len(groups) > 0 and not groups[0]['groups']: # 1. No groups available (for facility) and "no students" returned. messages.add_message( request, WARNING, _("No learner accounts have been created for selected facility/group." )) elif topic_id and playlist_id: # 2. Both topic and playlist are selected. messages.add_message( request, WARNING, _("Please select either a topic or a playlist above, but not both." )) elif not topic_id and not playlist_id: # 3. Group was selected, but data not queried because a topic or playlist was not selected. if playlists: # 4. No playlist was selected. messages.add_message(request, WARNING, _("Please select a playlist.")) elif topics: # 5. No topic was selected. messages.add_message(request, WARNING, _("Please select a topic.")) else: # 6. Everything specified, but no users fit the query. messages.add_message( request, WARNING, _("No learner accounts in this group have been created.")) # End: Validate results by showing user messages. log_coach_report_view(request) return context