updates from Gluejar/regluit
parent
406aec970a
commit
48d0a4fbf1
|
@ -53,8 +53,11 @@ class QuestionnaireAdmin(admin.ModelAdmin):
|
|||
readonly_fields = ('export',)
|
||||
|
||||
def export(self, obj):
|
||||
csv_url= reverse("export_csv", args=[obj.id,])
|
||||
return '<a href="%s">%s</a>' % (csv_url, _("Download data"))
|
||||
csv_url = reverse("export_csv", args=[obj.id,])
|
||||
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.short_description = _('Export to CSV')
|
||||
|
|
|
@ -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 %}
|
|
@ -9,6 +9,8 @@ urlpatterns = [
|
|||
questionnaire, name='questionnaire_noargs'),
|
||||
url(r'^csv/(?P<qid>\d+)/$',
|
||||
export_csv, name='export_csv'),
|
||||
url(r'^summary/(?P<qid>\d+)/$',
|
||||
export_summary, name='export_summary'),
|
||||
url(r'^(?P<runcode>[^/]+)/progress/$',
|
||||
get_async_progress, name='progress'),
|
||||
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'^(?P<runcode>[^/]+)/(?P<qs>[-]{0,1}\d+)/$',
|
||||
questionnaire, name='questionset'),
|
||||
url(r'^q/manage/csv/(\d+)/',
|
||||
export_csv, name="export_csv"),
|
||||
]
|
||||
|
||||
if not use_session:
|
||||
|
|
|
@ -41,7 +41,7 @@ def numal_sort(a, b):
|
|||
bnum, bstr = split_numal(b)
|
||||
cmpnum = cmp(anum, bnum)
|
||||
if(cmpnum == 0):
|
||||
return cmp(astr, bstr)
|
||||
return cmp(astr.lower(), bstr.lower())
|
||||
return cmpnum
|
||||
|
||||
def numal0_sort(a, b):
|
||||
|
|
|
@ -13,7 +13,7 @@ from django.http import HttpResponse, HttpResponseRedirect
|
|||
from django.template import RequestContext
|
||||
from django.core.urlresolvers import reverse
|
||||
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.views.generic.base import TemplateView
|
||||
from django.db import transaction
|
||||
|
@ -812,22 +812,25 @@ def _table_headers(questions):
|
|||
This will create separate columns for each multiple-choice possiblity
|
||||
and freeform options, to avoid mixing data types and make charting easier.
|
||||
"""
|
||||
ql = list(questions)
|
||||
ql.sort(lambda x, y: numal_sort(x.number, y.number))
|
||||
ql = list(questions.order_by(
|
||||
'questionset__sortid', 'number')
|
||||
)
|
||||
#ql.sort(lambda x, y: numal_sort(x.number, y.number))
|
||||
columns = []
|
||||
for q in ql:
|
||||
qnum = '{}.{}'.format(q.questionset.sortid, q.number)
|
||||
if q.type.startswith('choice-yesnocomment'):
|
||||
columns.extend([q.number, q.number + "-freeform"])
|
||||
columns.extend([qnum, qnum + "-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'):
|
||||
cl = [c.value for c in q.choice_set.all()]
|
||||
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':
|
||||
columns.append(q.number + '-freeform')
|
||||
columns.append(qnum + '-freeform')
|
||||
else:
|
||||
columns.append(q.number)
|
||||
columns.append(qnum)
|
||||
return columns
|
||||
|
||||
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):
|
||||
return ["%s/%s" % (subject.id, subject.ip_address), run.id]
|
||||
|
||||
@permission_required("questionnaire.export")
|
||||
|
||||
@login_required
|
||||
def export_csv(request, qid,
|
||||
extra_headings=default_extra_headings,
|
||||
extra_entries=default_extra_entries,
|
||||
|
@ -848,9 +852,12 @@ def export_csv(request, qid,
|
|||
qid -- questionnaire_id
|
||||
extra_headings -- customize the headings for extra columns,
|
||||
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
|
||||
"""
|
||||
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()
|
||||
|
||||
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)
|
||||
for choice in ans:
|
||||
col = None
|
||||
qnum = '{}.{}'.format(answer.question.questionset.sortid, answer.question.number)
|
||||
if type(choice) == list:
|
||||
# freeform choice
|
||||
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)
|
||||
col = coldict.get(answer.question.number + '-' + unicode(choice), None)
|
||||
col = coldict.get(qnum + '-' + unicode(choice), None)
|
||||
if col is None: # single-choice items
|
||||
if ((not qchoicedict[answer.question.id]) or
|
||||
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
|
||||
col = coldict.get(answer.question.number + '-freeform', None)
|
||||
col = coldict.get(qnum + '-freeform', None)
|
||||
if col is not None:
|
||||
row[col] = choice
|
||||
# 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))
|
||||
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
|
||||
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:
|
||||
answers = Answer.objects.all()
|
||||
if answer_filter:
|
||||
answers = answer_filter(answers)
|
||||
answers = answers.filter(question__questionset__questionnaire=questionnaire)
|
||||
questions = Question.objects.filter(
|
||||
questionset__questionnaire=questionnaire).order_by(
|
||||
|
|
Loading…
Reference in New Issue