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
579544ec
Commit
579544ec
authored
Sep 05, 2012
by
Calen Pennington
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #626 from MITx/feature/victor/answer-export
Feature/victor/answer export
parents
77029076
a8cd4633
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
109 additions
and
12 deletions
+109
-12
lms/djangoapps/courseware/grades.py
+68
-0
lms/djangoapps/courseware/views.py
+6
-6
lms/djangoapps/instructor/views.py
+30
-4
lms/templates/courseware/instructor_dashboard.html
+3
-0
lms/urls.py
+2
-2
No files found.
lms/djangoapps/courseware/grades.py
View file @
579544ec
...
...
@@ -4,11 +4,14 @@ from __future__ import division
import
random
import
logging
from
collections
import
defaultdict
from
django.conf
import
settings
from
django.contrib.auth.models
import
User
from
models
import
StudentModuleCache
from
module_render
import
get_module
,
get_instance_module
from
xmodule
import
graders
from
xmodule.capa_module
import
CapaModule
from
xmodule.course_module
import
CourseDescriptor
from
xmodule.graders
import
Score
from
models
import
StudentModule
...
...
@@ -24,6 +27,71 @@ def yield_module_descendents(module):
stack
.
extend
(
next_module
.
get_display_items
()
)
yield
next_module
def
yield_problems
(
request
,
course
,
student
):
"""
Return an iterator over capa_modules that this student has
potentially answered. (all that student has answered will definitely be in
the list, but there may be others as well).
"""
grading_context
=
course
.
grading_context
student_module_cache
=
StudentModuleCache
(
course
.
id
,
student
,
grading_context
[
'all_descriptors'
])
for
section_format
,
sections
in
grading_context
[
'graded_sections'
]
.
iteritems
():
for
section
in
sections
:
section_descriptor
=
section
[
'section_descriptor'
]
# If the student hasn't seen a single problem in the section, skip it.
skip
=
True
for
moduledescriptor
in
section
[
'xmoduledescriptors'
]:
if
student_module_cache
.
lookup
(
course
.
id
,
moduledescriptor
.
category
,
moduledescriptor
.
location
.
url
()):
skip
=
False
break
if
skip
:
continue
section_module
=
get_module
(
student
,
request
,
section_descriptor
.
location
,
student_module_cache
,
course
.
id
)
if
section_module
is
None
:
# student doesn't have access to this module, or something else
# went wrong.
# log.debug("couldn't get module for student {0} for section location {1}"
# .format(student.username, section_descriptor.location))
continue
for
problem
in
yield_module_descendents
(
section_module
):
if
isinstance
(
problem
,
CapaModule
):
yield
problem
def
answer_distributions
(
request
,
course
):
"""
Given a course_descriptor, compute frequencies of answers for each problem:
Format is:
dict: (problem url_name, problem display_name, problem_id) -> (dict : answer -> count)
TODO (vshnayder): this is currently doing a full linear pass through all
students and all problems. This will be just a little slow.
"""
counts
=
defaultdict
(
lambda
:
defaultdict
(
int
))
enrolled_students
=
User
.
objects
.
filter
(
courseenrollment__course_id
=
course
.
id
)
for
student
in
enrolled_students
:
for
capa_module
in
yield_problems
(
request
,
course
,
student
):
for
problem_id
in
capa_module
.
lcp
.
student_answers
:
answer
=
capa_module
.
lcp
.
student_answers
[
problem_id
]
key
=
(
capa_module
.
url_name
,
capa_module
.
display_name
,
problem_id
)
counts
[
key
][
answer
]
+=
1
return
counts
def
grade
(
student
,
request
,
course
,
student_module_cache
=
None
,
keep_raw_scores
=
False
):
"""
This grades a student as quickly as possible. It retuns the
...
...
lms/djangoapps/courseware/views.py
View file @
579544ec
import
csv
import
json
import
logging
import
urllib
import
itertools
import
StringIO
from
functools
import
partial
...
...
@@ -219,9 +221,9 @@ def jump_to(request, course_id, location):
# Rely on index to do all error handling and access control.
return
redirect
(
'courseware_position'
,
course_id
=
course_id
,
chapter
=
chapter
,
section
=
section
,
course_id
=
course_id
,
chapter
=
chapter
,
section
=
section
,
position
=
position
)
@ensure_csrf_cookie
def
course_info
(
request
,
course_id
):
...
...
@@ -342,7 +344,7 @@ def progress(request, course_id, student_id=None):
# NOTE: To make sure impersonation by instructor works, use
# student instead of request.user in the rest of the function.
# The pre-fetching of groups is done to make auth checks not require an
# The pre-fetching of groups is done to make auth checks not require an
# additional DB lookup (this kills the Progress page in particular).
student
=
User
.
objects
.
prefetch_related
(
"groups"
)
.
get
(
id
=
student
.
id
)
...
...
@@ -368,5 +370,3 @@ def progress(request, course_id, student_id=None):
return
render_to_response
(
'courseware/progress.html'
,
context
)
lms/djangoapps/instructor/views.py
View file @
579544ec
...
...
@@ -48,7 +48,7 @@ def instructor_dashboard(request, course_id):
"""Display the instructor dashboard for a course."""
course
=
get_course_with_access
(
request
.
user
,
course_id
,
'staff'
)
instructor_access
=
has_access
(
request
.
user
,
course
,
'instructor'
)
# an instructor can manage staff lists
instructor_access
=
has_access
(
request
.
user
,
course
,
'instructor'
)
# an instructor can manage staff lists
msg
=
''
# msg += ('POST=%s' % dict(request.POST)).replace('<','<')
...
...
@@ -99,7 +99,7 @@ def instructor_dashboard(request, course_id):
msg
+=
"git pull on
%
s:<p>"
%
data_dir
msg
+=
"<pre>
%
s</pre></p>"
%
escape
(
os
.
popen
(
cmd
)
.
read
())
track
.
views
.
server_track
(
request
,
'git pull
%
s'
%
data_dir
,
{},
page
=
'idashboard'
)
if
'Reload course'
in
action
:
log
.
debug
(
'reloading
%
s (
%
s)'
%
(
course_id
,
course
))
try
:
...
...
@@ -144,6 +144,10 @@ def instructor_dashboard(request, course_id):
return
return_csv
(
'grades_
%
s_raw.csv'
%
course_id
,
get_student_grade_summary_data
(
request
,
course
,
course_id
,
get_raw_scores
=
True
))
elif
'Download CSV of answer distributions'
in
action
:
track
.
views
.
server_track
(
request
,
'dump-answer-dist-csv'
,
{},
page
=
'idashboard'
)
return
return_csv
(
'answer_dist_
%
s.csv'
%
course_id
,
get_answers_distribution
(
request
,
course_id
))
elif
'List course staff'
in
action
:
group
=
get_staff_group
(
course
)
msg
+=
'Staff group =
%
s'
%
group
.
name
...
...
@@ -290,7 +294,7 @@ def grade_summary(request, course_id):
@ensure_csrf_cookie
@cache_control
(
no_cache
=
True
,
no_store
=
True
,
must_revalidate
=
True
)
def
enroll_students
(
request
,
course_id
):
'''
Allows a staff member to enroll students in a course.
"""
Allows a staff member to enroll students in a course.
This is a short-term hack for Berkeley courses launching fall
2012. In the long term, we would like functionality like this, but
...
...
@@ -300,7 +304,7 @@ def enroll_students(request, course_id):
It is poorly written and poorly tested, but it's designed to be
stripped out.
'''
"""
course
=
get_course_with_access
(
request
.
user
,
course_id
,
'staff'
)
existing_students
=
[
ce
.
user
.
email
for
ce
in
CourseEnrollment
.
objects
.
filter
(
course_id
=
course_id
)]
...
...
@@ -328,6 +332,28 @@ def enroll_students(request, course_id):
'rejected_students'
:
rejected_students
,
'debug'
:
new_students
})
def
get_answers_distribution
(
request
,
course_id
):
"""
Get the distribution of answers for all graded problems in the course.
Return a dict with two keys:
'header': a header row
'data': a list of rows
"""
course
=
get_course_with_access
(
request
.
user
,
course_id
,
'staff'
)
dist
=
grades
.
answer_distributions
(
request
,
course
)
d
=
{}
d
[
'header'
]
=
[
'url_name'
,
'display name'
,
'answer id'
,
'answer'
,
'count'
]
d
[
'data'
]
=
[[
url_name
,
display_name
,
answer_id
,
a
,
answers
[
a
]]
for
(
url_name
,
display_name
,
answer_id
),
answers
in
dist
.
items
()
for
a
in
answers
]
return
d
#-----------------------------------------------------------------------------
...
...
lms/templates/courseware/instructor_dashboard.html
View file @
579544ec
...
...
@@ -58,6 +58,9 @@ table.stat_table td {
<input
type=
"submit"
name=
"action"
value=
"Dump all RAW grades for all students in this course"
>
<input
type=
"submit"
name=
"action"
value=
"Download CSV of all RAW grades"
>
<p>
<input
type=
"submit"
name=
"action"
value=
"Download CSV of answer distributions"
>
%if instructor_access:
<hr
width=
"40%"
style=
"align:left"
>
<p>
...
...
lms/urls.py
View file @
579544ec
...
...
@@ -197,8 +197,8 @@ if settings.WIKI_ENABLED:
)
if
settings
.
QUICKEDIT
:
urlpatterns
+=
(
url
(
r'^quickedit/(?P<id>[^/]*)$'
,
'dogfood.views.quickedit'
),)
urlpatterns
+=
(
url
(
r'^dogfood/(?P<id>[^/]*)$'
,
'dogfood.views.df_capa_problem'
),)
urlpatterns
+=
(
url
(
r'^quickedit/(?P<id>[^/]*)$'
,
'dogfood.views.quickedit'
),)
urlpatterns
+=
(
url
(
r'^dogfood/(?P<id>[^/]*)$'
,
'dogfood.views.df_capa_problem'
),)
if
settings
.
ASKBOT_ENABLED
:
urlpatterns
+=
(
url
(
r'^
%
s'
%
settings
.
ASKBOT_URL
,
include
(
'askbot.urls'
)),
\
...
...
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