updates from Gluejar/regluit

dj111py38
eric 2017-06-08 17:28:18 -04:00
parent 406aec970a
commit 48d0a4fbf1
5 changed files with 87 additions and 20 deletions

View File

@ -53,8 +53,11 @@ class QuestionnaireAdmin(admin.ModelAdmin):
readonly_fields = ('export',) readonly_fields = ('export',)
def export(self, obj): def export(self, obj):
csv_url= reverse("export_csv", args=[obj.id,]) csv_url = reverse("export_csv", args=[obj.id,])
return '<a href="%s">%s</a>' % (csv_url, _("Download data")) summary_url = reverse("export_summary", args=[obj.id,])
return '<a href="{}">{}</a> <a href="{}">{}</a>'.format(
csv_url, _("Download data"), summary_url, _("Show summary")
)
export.allow_tags = True export.allow_tags = True
export.short_description = _('Export to CSV') export.short_description = _('Export to CSV')

View File

@ -0,0 +1,35 @@
{% extends "base-questionnaire.html" %}
{% block questionnaire %}
<h1>
Survey Results Summary
</h1>
{% for summary in summaries %}
<h2>Question</h2>
<p>
{{summary.1|safe}}
</p>
{% if summary.2 %}
<h3>Choices</h3>
<ul>
{% for option in summary.2 %}
<li>
{{option.1}}: <b>{{option.2}}</b>
</li>
{% endfor %}
</ul>
{% endif %}
<h3>Free Text Answers</h3>
<ul>
{% for answer in summary.3 %}
{% if answer %}
<li>
{{answer}}
</li>
{% endif %}
{% endfor %}
</ul>
{% endfor %}
{% endblock %}

View File

@ -9,6 +9,8 @@ urlpatterns = [
questionnaire, name='questionnaire_noargs'), questionnaire, name='questionnaire_noargs'),
url(r'^csv/(?P<qid>\d+)/$', url(r'^csv/(?P<qid>\d+)/$',
export_csv, name='export_csv'), export_csv, name='export_csv'),
url(r'^summary/(?P<qid>\d+)/$',
export_summary, name='export_summary'),
url(r'^(?P<runcode>[^/]+)/progress/$', url(r'^(?P<runcode>[^/]+)/progress/$',
get_async_progress, name='progress'), get_async_progress, name='progress'),
url(r'^take/(?P<questionnaire_id>[0-9]+)/$', generate_run), url(r'^take/(?P<questionnaire_id>[0-9]+)/$', generate_run),
@ -19,8 +21,6 @@ urlpatterns = [
url(r'^landing/(?P<nonce>\w+)/$', SurveyView.as_view(), name="landing"), url(r'^landing/(?P<nonce>\w+)/$', SurveyView.as_view(), name="landing"),
url(r'^(?P<runcode>[^/]+)/(?P<qs>[-]{0,1}\d+)/$', url(r'^(?P<runcode>[^/]+)/(?P<qs>[-]{0,1}\d+)/$',
questionnaire, name='questionset'), questionnaire, name='questionset'),
url(r'^q/manage/csv/(\d+)/',
export_csv, name="export_csv"),
] ]
if not use_session: if not use_session:

View File

@ -41,7 +41,7 @@ def numal_sort(a, b):
bnum, bstr = split_numal(b) bnum, bstr = split_numal(b)
cmpnum = cmp(anum, bnum) cmpnum = cmp(anum, bnum)
if(cmpnum == 0): if(cmpnum == 0):
return cmp(astr, bstr) return cmp(astr.lower(), bstr.lower())
return cmpnum return cmpnum
def numal0_sort(a, b): def numal0_sort(a, b):

View File

@ -13,7 +13,7 @@ from django.http import HttpResponse, HttpResponseRedirect
from django.template import RequestContext from django.template import RequestContext
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.core.cache import cache from django.core.cache import cache
from django.contrib.auth.decorators import permission_required from django.contrib.auth.decorators import login_required, permission_required
from django.shortcuts import render, render_to_response, get_object_or_404 from django.shortcuts import render, render_to_response, get_object_or_404
from django.views.generic.base import TemplateView from django.views.generic.base import TemplateView
from django.db import transaction from django.db import transaction
@ -812,22 +812,25 @@ def _table_headers(questions):
This will create separate columns for each multiple-choice possiblity This will create separate columns for each multiple-choice possiblity
and freeform options, to avoid mixing data types and make charting easier. and freeform options, to avoid mixing data types and make charting easier.
""" """
ql = list(questions) ql = list(questions.order_by(
ql.sort(lambda x, y: numal_sort(x.number, y.number)) 'questionset__sortid', 'number')
)
#ql.sort(lambda x, y: numal_sort(x.number, y.number))
columns = [] columns = []
for q in ql: for q in ql:
qnum = '{}.{}'.format(q.questionset.sortid, q.number)
if q.type.startswith('choice-yesnocomment'): if q.type.startswith('choice-yesnocomment'):
columns.extend([q.number, q.number + "-freeform"]) columns.extend([qnum, qnum + "-freeform"])
elif q.type.startswith('choice-freeform'): elif q.type.startswith('choice-freeform'):
columns.extend([q.number, q.number + "-freeform"]) columns.extend([qnum, qnum + "-freeform"])
elif q.type.startswith('choice-multiple'): elif q.type.startswith('choice-multiple'):
cl = [c.value for c in q.choice_set.all()] cl = [c.value for c in q.choice_set.all()]
cl.sort(numal_sort) cl.sort(numal_sort)
columns.extend([q.number + '-' + value for value in cl]) columns.extend([qnum + '-' + value for value in cl])
if q.type == 'choice-multiple-freeform': if q.type == 'choice-multiple-freeform':
columns.append(q.number + '-freeform') columns.append(qnum + '-freeform')
else: else:
columns.append(q.number) columns.append(qnum)
return columns return columns
default_extra_headings = [u'subject', u'run id'] default_extra_headings = [u'subject', u'run id']
@ -835,7 +838,8 @@ default_extra_headings = [u'subject', u'run id']
def default_extra_entries(subject, run): def default_extra_entries(subject, run):
return ["%s/%s" % (subject.id, subject.ip_address), run.id] return ["%s/%s" % (subject.id, subject.ip_address), run.id]
@permission_required("questionnaire.export")
@login_required
def export_csv(request, qid, def export_csv(request, qid,
extra_headings=default_extra_headings, extra_headings=default_extra_headings,
extra_entries=default_extra_entries, extra_entries=default_extra_entries,
@ -848,9 +852,12 @@ def export_csv(request, qid,
qid -- questionnaire_id qid -- questionnaire_id
extra_headings -- customize the headings for extra columns, extra_headings -- customize the headings for extra columns,
extra_entries -- function returning a list of extra column entries, extra_entries -- function returning a list of extra column entries,
answer_filter -- custom filter for the answers answer_filter -- custom filter for the answers. If this is present, the filter must manage access.
filecode -- code for filename filecode -- code for filename
""" """
if answer_filter is None and not request.user.has_perm("questionnaire.export"):
return HttpResponse('Sorry, you do not have export permissions', content_type="text/plain")
fd = tempfile.TemporaryFile() fd = tempfile.TemporaryFile()
questionnaire = get_object_or_404(Questionnaire, pk=int(qid)) questionnaire = get_object_or_404(Questionnaire, pk=int(qid))
@ -930,18 +937,19 @@ def answer_export(questionnaire, answers=None, answer_filter=None):
ans = str(ans) ans = str(ans)
for choice in ans: for choice in ans:
col = None col = None
qnum = '{}.{}'.format(answer.question.questionset.sortid, answer.question.number)
if type(choice) == list: if type(choice) == list:
# freeform choice # freeform choice
choice = choice[0] choice = choice[0]
col = coldict.get(answer.question.number + '-freeform', None) col = coldict.get(qnum + '-freeform', None)
if col is None: # look for enumerated choice column (multiple-choice) if col is None: # look for enumerated choice column (multiple-choice)
col = coldict.get(answer.question.number + '-' + unicode(choice), None) col = coldict.get(qnum + '-' + unicode(choice), None)
if col is None: # single-choice items if col is None: # single-choice items
if ((not qchoicedict[answer.question.id]) or if ((not qchoicedict[answer.question.id]) or
choice in qchoicedict[answer.question.id]): choice in qchoicedict[answer.question.id]):
col = coldict.get(answer.question.number, None) col = coldict.get(qnum, None)
if col is None: # last ditch, if not found throw it in a freeform column if col is None: # last ditch, if not found throw it in a freeform column
col = coldict.get(answer.question.number + '-freeform', None) col = coldict.get(qnum + '-freeform', None)
if col is not None: if col is not None:
row[col] = choice row[col] = choice
# and don't forget about the last one # and don't forget about the last one
@ -949,8 +957,27 @@ def answer_export(questionnaire, answers=None, answer_filter=None):
out.append((subject, run, row)) out.append((subject, run, row))
return headings, out return headings, out
@login_required
def export_summary(request, qid,
answer_filter=None,
):
"""
For a given questionnaire id, generate a CSV containing a summary of
answers for all subjects.
qid -- questionnaire_id
answer_filter -- custom filter for the answers. If this is present, the filter must manage access.
"""
if answer_filter is None and not request.user.has_perm("questionnaire.export"):
return HttpResponse('Sorry, you do not have export permissions', content_type="text/plain")
def answer_summary(questionnaire, answers=None): questionnaire = get_object_or_404(Questionnaire, pk=int(qid))
summaries = answer_summary(questionnaire, answer_filter=answer_filter)
return render(request, "pages/summaries.html", {'summaries':summaries})
def answer_summary(questionnaire, answers=None, answer_filter=None):
""" """
questionnaire -- questionnaire model for summary questionnaire -- questionnaire model for summary
answers -- query set of answers to include in summary, defaults to all answers -- query set of answers to include in summary, defaults to all
@ -967,6 +994,8 @@ def answer_summary(questionnaire, answers=None):
if answers is None: if answers is None:
answers = Answer.objects.all() answers = Answer.objects.all()
if answer_filter:
answers = answer_filter(answers)
answers = answers.filter(question__questionset__questionnaire=questionnaire) answers = answers.filter(question__questionset__questionnaire=questionnaire)
questions = Question.objects.filter( questions = Question.objects.filter(
questionset__questionnaire=questionnaire).order_by( questionset__questionnaire=questionnaire).order_by(