Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
E
edx-platform
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
edx-platform
Commits
04d6f08c
Commit
04d6f08c
authored
Jan 07, 2013
by
ichuang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add offline grade computation & DB table for this
parent
82e31d53
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
368 additions
and
23 deletions
+368
-23
common/djangoapps/student/admin.py
+2
-0
lms/djangoapps/courseware/access.py
+10
-4
lms/djangoapps/courseware/admin.py
+5
-0
lms/djangoapps/courseware/migrations/0005_auto__add_offlinecomputedgrade__add_unique_offlinecomputedgrade_user_c.py
+118
-0
lms/djangoapps/courseware/models.py
+37
-0
lms/djangoapps/instructor/management/commands/compute_grades.py
+50
-0
lms/djangoapps/instructor/offline_gradecalc.py
+103
-0
lms/djangoapps/instructor/views.py
+37
-19
lms/templates/courseware/instructor_dashboard.html
+6
-0
No files found.
common/djangoapps/student/admin.py
View file @
04d6f08c
...
...
@@ -12,6 +12,8 @@ admin.site.register(UserTestGroup)
admin
.
site
.
register
(
CourseEnrollment
)
admin
.
site
.
register
(
CourseEnrollmentAllowed
)
admin
.
site
.
register
(
Registration
)
admin
.
site
.
register
(
PendingNameChange
)
lms/djangoapps/courseware/access.py
View file @
04d6f08c
...
...
@@ -5,8 +5,6 @@ like DISABLE_START_DATES"""
import
logging
import
time
import
student.models
from
django.conf
import
settings
from
xmodule.course_module
import
CourseDescriptor
...
...
@@ -15,6 +13,13 @@ from xmodule.modulestore import Location
from
xmodule.timeparse
import
parse_time
from
xmodule.x_module
import
XModule
,
XModuleDescriptor
# student.models imports Role, which imports courseware.access ; use a try, to break the circular import
try
:
from
student.models
import
CourseEnrollmentAllowed
except
Exception
as
err
:
CourseEnrollmentAllowed
=
None
DEBUG_ACCESS
=
False
log
=
logging
.
getLogger
(
__name__
)
...
...
@@ -127,8 +132,9 @@ def _has_access_course_desc(user, course, action):
return
True
# if user is in CourseEnrollmentAllowed with right course_id then can also enroll
if
user
is
not
None
and
student
.
models
.
CourseEnrollmentAllowed
.
objects
.
filter
(
email
=
user
.
email
,
course_id
=
course
.
id
):
return
True
if
user
is
not
None
and
CourseEnrollmentAllowed
:
if
CourseEnrollmentAllowed
.
objects
.
filter
(
email
=
user
.
email
,
course_id
=
course
.
id
):
return
True
# otherwise, need staff access
return
_has_staff_access_to_descriptor
(
user
,
course
)
...
...
lms/djangoapps/courseware/admin.py
View file @
04d6f08c
...
...
@@ -7,3 +7,8 @@ from django.contrib import admin
from
django.contrib.auth.models
import
User
admin
.
site
.
register
(
StudentModule
)
admin
.
site
.
register
(
OfflineComputedGrade
)
admin
.
site
.
register
(
OfflineComputedGradeLog
)
lms/djangoapps/courseware/migrations/0005_auto__add_offlinecomputedgrade__add_unique_offlinecomputedgrade_user_c.py
0 → 100644
View file @
04d6f08c
# -*- coding: utf-8 -*-
import
datetime
from
south.db
import
db
from
south.v2
import
SchemaMigration
from
django.db
import
models
class
Migration
(
SchemaMigration
):
def
forwards
(
self
,
orm
):
# Adding model 'OfflineComputedGrade'
db
.
create_table
(
'courseware_offlinecomputedgrade'
,
(
(
'id'
,
self
.
gf
(
'django.db.models.fields.AutoField'
)(
primary_key
=
True
)),
(
'user'
,
self
.
gf
(
'django.db.models.fields.related.ForeignKey'
)(
to
=
orm
[
'auth.User'
])),
(
'course_id'
,
self
.
gf
(
'django.db.models.fields.CharField'
)(
max_length
=
255
,
db_index
=
True
)),
(
'created'
,
self
.
gf
(
'django.db.models.fields.DateTimeField'
)(
auto_now_add
=
True
,
null
=
True
,
db_index
=
True
,
blank
=
True
)),
(
'updated'
,
self
.
gf
(
'django.db.models.fields.DateTimeField'
)(
auto_now
=
True
,
db_index
=
True
,
blank
=
True
)),
(
'gradeset'
,
self
.
gf
(
'django.db.models.fields.TextField'
)(
null
=
True
,
blank
=
True
)),
))
db
.
send_create_signal
(
'courseware'
,
[
'OfflineComputedGrade'
])
# Adding unique constraint on 'OfflineComputedGrade', fields ['user', 'course_id']
db
.
create_unique
(
'courseware_offlinecomputedgrade'
,
[
'user_id'
,
'course_id'
])
# Adding model 'OfflineComputedGradeLog'
db
.
create_table
(
'courseware_offlinecomputedgradelog'
,
(
(
'id'
,
self
.
gf
(
'django.db.models.fields.AutoField'
)(
primary_key
=
True
)),
(
'course_id'
,
self
.
gf
(
'django.db.models.fields.CharField'
)(
max_length
=
255
,
db_index
=
True
)),
(
'created'
,
self
.
gf
(
'django.db.models.fields.DateTimeField'
)(
auto_now_add
=
True
,
null
=
True
,
db_index
=
True
,
blank
=
True
)),
(
'seconds'
,
self
.
gf
(
'django.db.models.fields.IntegerField'
)(
default
=
0
)),
(
'nstudents'
,
self
.
gf
(
'django.db.models.fields.IntegerField'
)(
default
=
0
)),
))
db
.
send_create_signal
(
'courseware'
,
[
'OfflineComputedGradeLog'
])
def
backwards
(
self
,
orm
):
# Removing unique constraint on 'OfflineComputedGrade', fields ['user', 'course_id']
db
.
delete_unique
(
'courseware_offlinecomputedgrade'
,
[
'user_id'
,
'course_id'
])
# Deleting model 'OfflineComputedGrade'
db
.
delete_table
(
'courseware_offlinecomputedgrade'
)
# Deleting model 'OfflineComputedGradeLog'
db
.
delete_table
(
'courseware_offlinecomputedgradelog'
)
models
=
{
'auth.group'
:
{
'Meta'
:
{
'object_name'
:
'Group'
},
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'80'
}),
'permissions'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
"orm['auth.Permission']"
,
'symmetrical'
:
'False'
,
'blank'
:
'True'
})
},
'auth.permission'
:
{
'Meta'
:
{
'ordering'
:
"('content_type__app_label', 'content_type__model', 'codename')"
,
'unique_together'
:
"(('content_type', 'codename'),)"
,
'object_name'
:
'Permission'
},
'codename'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
}),
'content_type'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['contenttypes.ContentType']"
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'50'
})
},
'auth.user'
:
{
'Meta'
:
{
'object_name'
:
'User'
},
'date_joined'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'email'
:
(
'django.db.models.fields.EmailField'
,
[],
{
'max_length'
:
'75'
,
'blank'
:
'True'
}),
'first_name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'30'
,
'blank'
:
'True'
}),
'groups'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
"orm['auth.Group']"
,
'symmetrical'
:
'False'
,
'blank'
:
'True'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'is_active'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'True'
}),
'is_staff'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'is_superuser'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'last_login'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'default'
:
'datetime.datetime.now'
}),
'last_name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'30'
,
'blank'
:
'True'
}),
'password'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'128'
}),
'user_permissions'
:
(
'django.db.models.fields.related.ManyToManyField'
,
[],
{
'to'
:
"orm['auth.Permission']"
,
'symmetrical'
:
'False'
,
'blank'
:
'True'
}),
'username'
:
(
'django.db.models.fields.CharField'
,
[],
{
'unique'
:
'True'
,
'max_length'
:
'30'
})
},
'contenttypes.contenttype'
:
{
'Meta'
:
{
'ordering'
:
"('name',)"
,
'unique_together'
:
"(('app_label', 'model'),)"
,
'object_name'
:
'ContentType'
,
'db_table'
:
"'django_content_type'"
},
'app_label'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'model'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
}),
'name'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'100'
})
},
'courseware.offlinecomputedgrade'
:
{
'Meta'
:
{
'unique_together'
:
"(('user', 'course_id'),)"
,
'object_name'
:
'OfflineComputedGrade'
},
'course_id'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'255'
,
'db_index'
:
'True'
}),
'created'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now_add'
:
'True'
,
'null'
:
'True'
,
'db_index'
:
'True'
,
'blank'
:
'True'
}),
'gradeset'
:
(
'django.db.models.fields.TextField'
,
[],
{
'null'
:
'True'
,
'blank'
:
'True'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'updated'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now'
:
'True'
,
'db_index'
:
'True'
,
'blank'
:
'True'
}),
'user'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['auth.User']"
})
},
'courseware.offlinecomputedgradelog'
:
{
'Meta'
:
{
'object_name'
:
'OfflineComputedGradeLog'
},
'course_id'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'255'
,
'db_index'
:
'True'
}),
'created'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now_add'
:
'True'
,
'null'
:
'True'
,
'db_index'
:
'True'
,
'blank'
:
'True'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'nstudents'
:
(
'django.db.models.fields.IntegerField'
,
[],
{
'default'
:
'0'
}),
'seconds'
:
(
'django.db.models.fields.IntegerField'
,
[],
{
'default'
:
'0'
})
},
'courseware.studentmodule'
:
{
'Meta'
:
{
'unique_together'
:
"(('student', 'module_state_key', 'course_id'),)"
,
'object_name'
:
'StudentModule'
},
'course_id'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'255'
,
'db_index'
:
'True'
}),
'created'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now_add'
:
'True'
,
'db_index'
:
'True'
,
'blank'
:
'True'
}),
'done'
:
(
'django.db.models.fields.CharField'
,
[],
{
'default'
:
"'na'"
,
'max_length'
:
'8'
,
'db_index'
:
'True'
}),
'grade'
:
(
'django.db.models.fields.FloatField'
,
[],
{
'db_index'
:
'True'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'max_grade'
:
(
'django.db.models.fields.FloatField'
,
[],
{
'null'
:
'True'
,
'blank'
:
'True'
}),
'modified'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now'
:
'True'
,
'db_index'
:
'True'
,
'blank'
:
'True'
}),
'module_state_key'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'255'
,
'db_column'
:
"'module_id'"
,
'db_index'
:
'True'
}),
'module_type'
:
(
'django.db.models.fields.CharField'
,
[],
{
'default'
:
"'problem'"
,
'max_length'
:
'32'
,
'db_index'
:
'True'
}),
'state'
:
(
'django.db.models.fields.TextField'
,
[],
{
'null'
:
'True'
,
'blank'
:
'True'
}),
'student'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['auth.User']"
})
}
}
complete_apps
=
[
'courseware'
]
\ No newline at end of file
lms/djangoapps/courseware/models.py
View file @
04d6f08c
...
...
@@ -177,3 +177,40 @@ class StudentModuleCache(object):
def
append
(
self
,
student_module
):
self
.
cache
.
append
(
student_module
)
class
OfflineComputedGrade
(
models
.
Model
):
"""
Table of grades computed offline for a given user and course.
"""
user
=
models
.
ForeignKey
(
User
,
db_index
=
True
)
course_id
=
models
.
CharField
(
max_length
=
255
,
db_index
=
True
)
created
=
models
.
DateTimeField
(
auto_now_add
=
True
,
null
=
True
,
db_index
=
True
)
updated
=
models
.
DateTimeField
(
auto_now
=
True
,
db_index
=
True
)
gradeset
=
models
.
TextField
(
null
=
True
,
blank
=
True
)
# grades, stored as JSON
class
Meta
:
unique_together
=
((
'user'
,
'course_id'
),
)
def
__unicode__
(
self
):
return
"[OfflineComputedGrade]
%
s:
%
s (
%
s) =
%
s"
%
(
self
.
user
,
self
.
course_id
,
self
.
created
,
self
.
gradeset
)
class
OfflineComputedGradeLog
(
models
.
Model
):
"""
Log of when offline grades are computed.
Use this to be able to show instructor when the last computed grades were done.
"""
class
Meta
:
ordering
=
[
"-created"
]
get_latest_by
=
"created"
course_id
=
models
.
CharField
(
max_length
=
255
,
db_index
=
True
)
created
=
models
.
DateTimeField
(
auto_now_add
=
True
,
null
=
True
,
db_index
=
True
)
seconds
=
models
.
IntegerField
(
default
=
0
)
# seconds elapsed for computation
nstudents
=
models
.
IntegerField
(
default
=
0
)
def
__unicode__
(
self
):
return
"[OCGLog]
%
s:
%
s"
%
(
self
.
course_id
,
self
.
created
)
lms/djangoapps/instructor/management/commands/compute_grades.py
0 → 100644
View file @
04d6f08c
#!/usr/bin/python
#
# django management command: dump grades to csv files
# for use by batch processes
import
os
,
sys
,
string
import
datetime
import
json
#import student.models
from
instructor.offline_gradecalc
import
*
from
courseware.courses
import
get_course_by_id
from
xmodule.modulestore.django
import
modulestore
from
django.conf
import
settings
from
django.core.management.base
import
BaseCommand
class
Command
(
BaseCommand
):
help
=
"Compute grades for all students in a course, and store result in DB.
\n
"
help
+=
"Usage: compute_grades course_id_or_dir
\n
"
help
+=
" course_id_or_dir: either course_id or course_dir
\n
"
def
handle
(
self
,
*
args
,
**
options
):
print
"args = "
,
args
course_id
=
'MITx/8.01rq_MW/Classical_Mechanics_Reading_Questions_Fall_2012_MW_Section'
if
len
(
args
)
>
0
:
course_id
=
args
[
0
]
try
:
course
=
get_course_by_id
(
course_id
)
except
Exception
as
err
:
if
course_id
in
modulestore
()
.
courses
:
course
=
modulestore
()
.
courses
[
course_id
]
else
:
print
"-----------------------------------------------------------------------------"
print
"Sorry, cannot find course
%
s"
%
course_id
print
"Please provide a course ID or course data directory name, eg content-mit-801rq"
return
print
"-----------------------------------------------------------------------------"
print
"Computing grades for
%
s"
%
(
course
.
id
)
offline_grade_calculation
(
course
.
id
)
lms/djangoapps/instructor/offline_gradecalc.py
0 → 100644
View file @
04d6f08c
# ======== Offline calculation of grades =============================================================================
#
# Computing grades of a large number of students can take a long time. These routines allow grades to
# be computed offline, by a batch process (eg cronjob).
#
# The grades are stored in the OfflineComputedGrade table of the courseware model.
import
json
import
logging
import
time
import
courseware.models
from
collections
import
namedtuple
from
json
import
JSONEncoder
from
courseware
import
grades
,
models
from
courseware.courses
import
get_course_by_id
from
django.contrib.auth.models
import
User
,
Group
class
MyEncoder
(
JSONEncoder
):
def
_iterencode
(
self
,
obj
,
markers
=
None
):
if
isinstance
(
obj
,
tuple
)
and
hasattr
(
obj
,
'_asdict'
):
gen
=
self
.
_iterencode_dict
(
obj
.
_asdict
(),
markers
)
else
:
gen
=
JSONEncoder
.
_iterencode
(
self
,
obj
,
markers
)
for
chunk
in
gen
:
yield
chunk
def
offline_grade_calculation
(
course_id
):
'''
Compute grades for all students for a specified course, and save results to the DB.
'''
tstart
=
time
.
time
()
enrolled_students
=
User
.
objects
.
filter
(
courseenrollment__course_id
=
course_id
)
.
prefetch_related
(
"groups"
)
.
order_by
(
'username'
)
enc
=
MyEncoder
()
class
DummyRequest
(
object
):
META
=
{}
def
__init__
(
self
):
return
def
get_host
(
self
):
return
'edx.mit.edu'
def
is_secure
(
self
):
return
False
request
=
DummyRequest
()
print
"
%
d enrolled students"
%
len
(
enrolled_students
)
course
=
get_course_by_id
(
course_id
)
for
student
in
enrolled_students
:
gradeset
=
grades
.
grade
(
student
,
request
,
course
,
keep_raw_scores
=
True
)
gs
=
enc
.
encode
(
gradeset
)
ocg
,
created
=
models
.
OfflineComputedGrade
.
objects
.
get_or_create
(
user
=
student
,
course_id
=
course_id
)
ocg
.
gradeset
=
gs
ocg
.
save
()
print
"
%
s done"
%
student
# print statement used because this is run by a management command
tend
=
time
.
time
()
dt
=
tend
-
tstart
ocgl
=
models
.
OfflineComputedGradeLog
(
course_id
=
course_id
,
seconds
=
dt
,
nstudents
=
len
(
enrolled_students
))
ocgl
.
save
()
print
ocgl
print
"All Done!"
def
offline_grades_available
(
course_id
):
'''
Returns False if no offline grades available for specified course.
Otherwise returns latest log field entry about the available pre-computed grades.
'''
ocgl
=
models
.
OfflineComputedGradeLog
.
objects
.
filter
(
course_id
=
course_id
)
if
not
ocgl
:
return
False
return
ocgl
.
latest
(
'created'
)
def
student_grades
(
student
,
request
,
course
,
keep_raw_scores
=
False
,
use_offline
=
False
):
'''
This is the main interface to get grades. It has the same parameters as grades.grade, as well
as use_offline. If use_offline is True then this will look for an offline computed gradeset in the DB.
'''
if
not
use_offline
:
return
grades
.
grade
(
student
,
request
,
course
,
keep_raw_scores
=
keep_raw_scores
)
try
:
ocg
=
models
.
OfflineComputedGrade
.
objects
.
get
(
user
=
student
,
course_id
=
course
.
id
)
except
models
.
OfflineComputedGrade
.
DoesNotExist
:
return
dict
(
raw_scores
=
[],
section_breakdown
=
[],
msg
=
'Error: no offline gradeset available for
%
s,
%
s'
%
(
student
,
course
.
id
))
return
json
.
loads
(
ocg
.
gradeset
)
lms/djangoapps/instructor/views.py
View file @
04d6f08c
...
...
@@ -32,7 +32,8 @@ from xmodule.modulestore.exceptions import InvalidLocationError, ItemNotFoundErr
from
xmodule.modulestore.search
import
path_to_location
import
track.views
from
.grading
import
StaffGrading
from
.offline_gradecalc
import
student_grades
,
offline_grades_available
log
=
logging
.
getLogger
(
__name__
)
...
...
@@ -103,6 +104,7 @@ def instructor_dashboard(request, course_id):
# process actions from form POST
action
=
request
.
POST
.
get
(
'action'
,
''
)
use_offline
=
request
.
POST
.
get
(
'use_offline_grades'
,
False
)
if
settings
.
MITX_FEATURES
[
'ENABLE_MANUAL_GIT_RELOAD'
]:
if
'GIT pull'
in
action
:
...
...
@@ -134,32 +136,32 @@ def instructor_dashboard(request, course_id):
if
action
==
'Dump list of enrolled students'
or
action
==
'List enrolled students'
:
log
.
debug
(
action
)
datatable
=
get_student_grade_summary_data
(
request
,
course
,
course_id
,
get_grades
=
False
)
datatable
=
get_student_grade_summary_data
(
request
,
course
,
course_id
,
get_grades
=
False
,
use_offline
=
use_offline
)
datatable
[
'title'
]
=
'List of students enrolled in {0}'
.
format
(
course_id
)
track
.
views
.
server_track
(
request
,
'list-students'
,
{},
page
=
'idashboard'
)
elif
'Dump Grades'
in
action
:
log
.
debug
(
action
)
datatable
=
get_student_grade_summary_data
(
request
,
course
,
course_id
,
get_grades
=
True
)
datatable
=
get_student_grade_summary_data
(
request
,
course
,
course_id
,
get_grades
=
True
,
use_offline
=
use_offline
)
datatable
[
'title'
]
=
'Summary Grades of students enrolled in {0}'
.
format
(
course_id
)
track
.
views
.
server_track
(
request
,
'dump-grades'
,
{},
page
=
'idashboard'
)
elif
'Dump all RAW grades'
in
action
:
log
.
debug
(
action
)
datatable
=
get_student_grade_summary_data
(
request
,
course
,
course_id
,
get_grades
=
True
,
get_raw_scores
=
True
)
get_raw_scores
=
True
,
use_offline
=
use_offline
)
datatable
[
'title'
]
=
'Raw Grades of students enrolled in {0}'
.
format
(
course_id
)
track
.
views
.
server_track
(
request
,
'dump-grades-raw'
,
{},
page
=
'idashboard'
)
elif
'Download CSV of all student grades'
in
action
:
track
.
views
.
server_track
(
request
,
'dump-grades-csv'
,
{},
page
=
'idashboard'
)
return
return_csv
(
'grades_{0}.csv'
.
format
(
course_id
),
get_student_grade_summary_data
(
request
,
course
,
course_id
))
get_student_grade_summary_data
(
request
,
course
,
course_id
,
use_offline
=
use_offline
))
elif
'Download CSV of all RAW grades'
in
action
:
track
.
views
.
server_track
(
request
,
'dump-grades-csv-raw'
,
{},
page
=
'idashboard'
)
return
return_csv
(
'grades_{0}_raw.csv'
.
format
(
course_id
),
get_student_grade_summary_data
(
request
,
course
,
course_id
,
get_raw_scores
=
True
))
get_student_grade_summary_data
(
request
,
course
,
course_id
,
get_raw_scores
=
True
,
use_offline
=
use_offline
))
elif
'Download CSV of answer distributions'
in
action
:
track
.
views
.
server_track
(
request
,
'dump-answer-dist-csv'
,
{},
page
=
'idashboard'
)
...
...
@@ -174,7 +176,7 @@ def instructor_dashboard(request, course_id):
elif
action
==
'List assignments available for this course'
:
log
.
debug
(
action
)
allgrades
=
get_student_grade_summary_data
(
request
,
course
,
course_id
,
get_grades
=
True
)
allgrades
=
get_student_grade_summary_data
(
request
,
course
,
course_id
,
get_grades
=
True
,
use_offline
=
use_offline
)
assignments
=
[[
x
]
for
x
in
allgrades
[
'assignments'
]]
datatable
=
{
'header'
:
[
'Assignment Name'
]}
...
...
@@ -184,7 +186,7 @@ def instructor_dashboard(request, course_id):
msg
+=
'assignments=<pre>
%
s</pre>'
%
assignments
elif
action
==
'List enrolled students matching remote gradebook'
:
stud_data
=
get_student_grade_summary_data
(
request
,
course
,
course_id
,
get_grades
=
False
)
stud_data
=
get_student_grade_summary_data
(
request
,
course
,
course_id
,
get_grades
=
False
,
use_offline
=
use_offline
)
msg2
,
rg_stud_data
=
_do_remote_gradebook
(
request
.
user
,
course
,
'get-membership'
)
datatable
=
{
'header'
:
[
'Student email'
,
'Match?'
]}
rg_students
=
[
x
[
'email'
]
for
x
in
rg_stud_data
[
'retdata'
]
]
...
...
@@ -202,7 +204,7 @@ def instructor_dashboard(request, course_id):
if
not
aname
:
msg
+=
"<font color='red'>Please enter an assignment name</font>"
else
:
allgrades
=
get_student_grade_summary_data
(
request
,
course
,
course_id
,
get_grades
=
True
)
allgrades
=
get_student_grade_summary_data
(
request
,
course
,
course_id
,
get_grades
=
True
,
use_offline
=
use_offline
)
if
aname
not
in
allgrades
[
'assignments'
]:
msg
+=
"<font color='red'>Invalid assignment name '
%
s'</font>"
%
aname
else
:
...
...
@@ -402,6 +404,12 @@ def instructor_dashboard(request, course_id):
#----------------------------------------
# offline grades?
if
use_offline
:
msg
+=
"<br/><font color='orange'>Grades from
%
s</font>"
%
offline_grades_available
(
course_id
)
#----------------------------------------
# context for rendering
context
=
{
'course'
:
course
,
...
...
@@ -416,7 +424,8 @@ def instructor_dashboard(request, course_id):
'plots'
:
plots
,
# psychometrics
'course_errors'
:
modulestore
()
.
get_item_errors
(
course
.
location
),
'djangopid'
:
os
.
getpid
(),
'mitx_version'
:
getattr
(
settings
,
'MITX_VERSION_STRING'
,
''
)
'mitx_version'
:
getattr
(
settings
,
'MITX_VERSION_STRING'
,
''
),
'offline_grade_log'
:
offline_grades_available
(
course_id
),
}
return
render_to_response
(
'courseware/instructor_dashboard.html'
,
context
)
...
...
@@ -539,7 +548,7 @@ def _update_forum_role_membership(uname, course, rolename, add_or_remove):
return
msg
def
get_student_grade_summary_data
(
request
,
course
,
course_id
,
get_grades
=
True
,
get_raw_scores
=
False
):
def
get_student_grade_summary_data
(
request
,
course
,
course_id
,
get_grades
=
True
,
get_raw_scores
=
False
,
use_offline
=
False
):
'''
Return data arrays with student identity and grades for specified course.
...
...
@@ -563,7 +572,7 @@ def get_student_grade_summary_data(request, course, course_id, get_grades=True,
assignments
=
[]
if
get_grades
and
enrolled_students
.
count
()
>
0
:
# just to construct the header
gradeset
=
grades
.
grade
(
enrolled_students
[
0
],
request
,
course
,
keep_raw_scores
=
get_raw_scores
)
gradeset
=
student_grades
(
enrolled_students
[
0
],
request
,
course
,
keep_raw_scores
=
get_raw_scores
,
use_offline
=
use_offline
)
# log.debug('student {0} gradeset {1}'.format(enrolled_students[0], gradeset))
if
get_raw_scores
:
assignments
+=
[
score
.
section
for
score
in
gradeset
[
'raw_scores'
]]
...
...
@@ -582,20 +591,22 @@ def get_student_grade_summary_data(request, course, course_id, get_grades=True,
datarow
.
append
(
''
)
if
get_grades
:
gradeset
=
grades
.
grade
(
student
,
request
,
course
,
keep_raw_scores
=
get_raw_scores
)
gradeset
=
student_grades
(
student
,
request
,
course
,
keep_raw_scores
=
get_raw_scores
,
use_offline
=
use_offline
)
log
.
debug
(
'student={0}, gradeset={1}'
.
format
(
student
,
gradeset
))
if
get_raw_scores
:
student_grades
=
[
score
.
earned
for
score
in
gradeset
[
'raw_scores'
]]
# TODO (ichuang) encode Score as dict instead of as list, so score[0] -> score['earned']
sgrades
=
[(
getattr
(
score
,
'earned'
,
''
)
or
score
[
0
])
for
score
in
gradeset
[
'raw_scores'
]]
else
:
s
tudent_
grades
=
[
x
[
'percent'
]
for
x
in
gradeset
[
'section_breakdown'
]]
datarow
+=
s
tudent_
grades
student
.
grades
=
s
tudent_
grades
# store in student object
sgrades
=
[
x
[
'percent'
]
for
x
in
gradeset
[
'section_breakdown'
]]
datarow
+=
sgrades
student
.
grades
=
sgrades
# store in student object
data
.
append
(
datarow
)
datatable
[
'data'
]
=
data
return
datatable
#-----------------------------------------------------------------------------
# Staff grading
...
...
@@ -616,7 +627,7 @@ def gradebook(request, course_id):
student_info
=
[{
'username'
:
student
.
username
,
'id'
:
student
.
id
,
'email'
:
student
.
email
,
'grade_summary'
:
grades
.
grade
(
student
,
request
,
course
),
'grade_summary'
:
student_grades
(
student
,
request
,
course
),
'realname'
:
student
.
profile
.
name
,
}
for
student
in
enrolled_students
]
...
...
@@ -639,6 +650,10 @@ def grade_summary(request, course_id):
return
render_to_response
(
'courseware/grade_summary.html'
,
context
)
#-----------------------------------------------------------------------------
# enrollment
def
_do_enroll_students
(
course
,
course_id
,
students
,
overload
=
False
):
"""Do the actual work of enrolling multiple students, presented as a string
of emails separated by commas or returns"""
...
...
@@ -731,6 +746,9 @@ def enroll_students(request, course_id):
'debug'
:
new_students
})
#-----------------------------------------------------------------------------
# answer distribution
def
get_answers_distribution
(
request
,
course_id
):
"""
Get the distribution of answers for all graded problems in the course.
...
...
lms/templates/courseware/instructor_dashboard.html
View file @
04d6f08c
...
...
@@ -71,6 +71,12 @@ function goto( mode)
##-----------------------------------------------------------------------------
%if modeflag.get('Grades'):
%if offline_grade_log:
<p><font
color=
'orange'
>
Pre-computed grades ${offline_grade_log} available: Use?
<input
type=
'checkbox'
name=
'use_offline_grades'
value=
'yes'
></font>
</p>
%endif
<p>
<a
href=
"${reverse('gradebook', kwargs=dict(course_id=course.id))}"
>
Gradebook
</a>
</p>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment