basic.py 3.63 KB
Newer Older
1 2 3 4 5 6 7 8 9 10
"""
Student and course analytics.

Serve miscellaneous course and student data
"""

from django.contrib.auth.models import User
import xmodule.graders as xmgraders


Miles Steele committed
11
STUDENT_FEATURES = ('username', 'first_name', 'last_name', 'is_staff', 'email')
12 13
PROFILE_FEATURES = ('name', 'language', 'location', 'year_of_birth', 'gender',
                    'level_of_education', 'mailing_address', 'goals')
Miles Steele committed
14
AVAILABLE_FEATURES = STUDENT_FEATURES + PROFILE_FEATURES
15 16


17
def enrolled_students_features(course_id, features):
18
    """
19 20
    Return list of student features as dictionaries.

21
    enrolled_students_features(course_id, ['username, first_name'])
22 23 24 25 26
    would return [
        {'username': 'username1', 'first_name': 'firstname1'}
        {'username': 'username2', 'first_name': 'firstname2'}
        {'username': 'username3', 'first_name': 'firstname3'}
    ]
27
    """
28 29
    students = User.objects.filter(courseenrollment__course_id=course_id)\
        .order_by('username').select_related('profile')
30

31
    def extract_student(student, features):
32 33 34
        """ convert student to dictionary """
        student_features = [x for x in STUDENT_FEATURES if x in features]
        profile_features = [x for x in PROFILE_FEATURES if x in features]
35

36 37
        student_dict = dict((feature, getattr(student, feature))
                            for feature in student_features)
38
        profile = student.profile
39
        if profile is not None:
40 41 42
            profile_dict = dict((feature, getattr(profile, feature))
                                for feature in profile_features)
            student_dict.update(profile_dict)
43 44
        return student_dict

45
    return [extract_student(student, features) for student in students]
46 47 48 49


def dump_grading_context(course):
    """
50 51
    Render information about course grading context
    (e.g. which problems are graded in what assignments)
52 53 54 55
    Useful for debugging grading_policy.json and policy.json

    Returns HTML string
    """
56 57
    hbar = "{}\n".format("-" * 77)
    msg = hbar
58 59 60 61 62 63 64 65
    msg += "Course grader:\n"

    msg += '%s\n' % course.grader.__class__
    graders = {}
    if isinstance(course.grader, xmgraders.WeightedSubsectionsGrader):
        msg += '\n'
        msg += "Graded sections:\n"
        for subgrader, category, weight in course.grader.sections:
66 67
            msg += "  subgrader=%s, type=%s, category=%s, weight=%s\n"\
                % (subgrader.__class__, subgrader.type, category, weight)
68 69
            subgrader.index = 1
            graders[subgrader.type] = subgrader
70
    msg += hbar
71 72
    msg += "Listing grading context for course %s\n" % course.id

73
    gcontext = course.grading_context
74 75
    msg += "graded sections:\n"

76 77 78
    msg += '%s\n' % gcontext['graded_sections'].keys()
    for (gsomething, gsvals) in gcontext['graded_sections'].items():
        msg += "--> Section %s:\n" % (gsomething)
79
        for sec in gsvals:
80 81
            sdesc = sec['section_descriptor']
            frmat = getattr(sdesc.lms, 'format', None)
82
            aname = ''
83 84 85 86 87 88 89
            if frmat in graders:
                gform = graders[frmat]
                aname = '%s %02d' % (gform.short_label, gform.index)
                gform.index += 1
            elif sdesc.display_name in graders:
                gform = graders[sdesc.display_name]
                aname = '%s' % gform.short_label
90
            notes = ''
91
            if getattr(sdesc, 'score_by_attempt', False):
92
                notes = ', score by attempt!'
93 94
            msg += "      %s (format=%s, Assignment=%s%s)\n"\
                % (sdesc.display_name, frmat, aname, notes)
95
    msg += "all descriptors:\n"
96 97
    msg += "length=%d\n" % len(gcontext['all_descriptors'])
    msg = '<pre>%s</pre>' % msg.replace('<', '&lt;')
98
    return msg