Commit 1881b3ab8fde04e7401bd733c19a2ec1ba6de559
Exists in
master
and in
3 other branches
Merge branch 'refactoring' of https://github.com/amadeusproject/amadeuslms into refactoring
Showing
8 changed files
with
154 additions
and
31 deletions
Show diff stats
... | ... | @@ -0,0 +1,20 @@ |
1 | +# -*- coding: utf-8 -*- | |
2 | +# Generated by Django 1.10.4 on 2017-03-23 18:17 | |
3 | +from __future__ import unicode_literals | |
4 | + | |
5 | +from django.db import migrations, models | |
6 | + | |
7 | + | |
8 | +class Migration(migrations.Migration): | |
9 | + | |
10 | + dependencies = [ | |
11 | + ('reports', '0002_reportxls'), | |
12 | + ] | |
13 | + | |
14 | + operations = [ | |
15 | + migrations.AlterField( | |
16 | + model_name='reportxls', | |
17 | + name='xls_data', | |
18 | + field=models.TextField(null=True), | |
19 | + ), | |
20 | + ] | ... | ... |
... | ... | @@ -0,0 +1,20 @@ |
1 | +# -*- coding: utf-8 -*- | |
2 | +# Generated by Django 1.10.4 on 2017-03-23 18:20 | |
3 | +from __future__ import unicode_literals | |
4 | + | |
5 | +from django.db import migrations, models | |
6 | + | |
7 | + | |
8 | +class Migration(migrations.Migration): | |
9 | + | |
10 | + dependencies = [ | |
11 | + ('reports', '0003_auto_20170323_1517'), | |
12 | + ] | |
13 | + | |
14 | + operations = [ | |
15 | + migrations.AlterField( | |
16 | + model_name='reportxls', | |
17 | + name='xls_data', | |
18 | + field=models.TextField(), | |
19 | + ), | |
20 | + ] | ... | ... |
... | ... | @@ -0,0 +1,20 @@ |
1 | +# -*- coding: utf-8 -*- | |
2 | +# Generated by Django 1.10.4 on 2017-03-23 19:03 | |
3 | +from __future__ import unicode_literals | |
4 | + | |
5 | +from django.db import migrations, models | |
6 | + | |
7 | + | |
8 | +class Migration(migrations.Migration): | |
9 | + | |
10 | + dependencies = [ | |
11 | + ('reports', '0004_auto_20170323_1520'), | |
12 | + ] | |
13 | + | |
14 | + operations = [ | |
15 | + migrations.AlterField( | |
16 | + model_name='reportxls', | |
17 | + name='xls_data', | |
18 | + field=models.FileField(upload_to='excel/'), | |
19 | + ), | |
20 | + ] | ... | ... |
... | ... | @@ -0,0 +1,20 @@ |
1 | +# -*- coding: utf-8 -*- | |
2 | +# Generated by Django 1.10.4 on 2017-03-23 19:29 | |
3 | +from __future__ import unicode_literals | |
4 | + | |
5 | +from django.db import migrations, models | |
6 | + | |
7 | + | |
8 | +class Migration(migrations.Migration): | |
9 | + | |
10 | + dependencies = [ | |
11 | + ('reports', '0005_auto_20170323_1603'), | |
12 | + ] | |
13 | + | |
14 | + operations = [ | |
15 | + migrations.AlterField( | |
16 | + model_name='reportxls', | |
17 | + name='xls_data', | |
18 | + field=models.FileField(upload_to='files/'), | |
19 | + ), | |
20 | + ] | ... | ... |
reports/models.py
reports/templates/reports/view.html
... | ... | @@ -65,10 +65,11 @@ |
65 | 65 | <ul id="report-info"> |
66 | 66 | <li> {{data.values|length}} {% trans "register(s)" %} </li> |
67 | 67 | <li> |
68 | - <a href="{% url 'subjects:reports:download_report_csv' %}"><i class="fa fa-download" aria-hidden="true"></i> {% trans "Interactions Data" %}</a> | |
68 | + <a href="{% url 'subjects:reports:download_report_csv' %}"><i class="fa fa-download" aria-hidden="true"></i> {% trans "Interactions Data (.csv)" %}</a> | |
69 | 69 | |
70 | 70 | |
71 | 71 | </li> |
72 | + <li><a href="{% url 'subjects:reports:download_report_xls' %}"><i class="fa fa-download" aria-hidden="true"></i> {% trans "Interactions Data (.xls)" %}</a></li> | |
72 | 73 | </ul> |
73 | 74 | |
74 | 75 | ... | ... |
reports/urls.py
... | ... | @@ -8,4 +8,5 @@ urlpatterns = [ |
8 | 8 | url(r'^get/resources/$', views.get_resources, name='get_resource_and_tags'), |
9 | 9 | url(r'^get/tags/$', views.get_tags, name='get_tags'), |
10 | 10 | url(r'^post/download_report/$', views.download_report_csv, name="download_report_csv"), |
11 | + url(r'^post/download_report/excel$', views.download_report_xls, name="download_report_xls"), | |
11 | 12 | ] |
12 | 13 | \ No newline at end of file | ... | ... |
reports/views.py
... | ... | @@ -4,9 +4,9 @@ from django.utils.translation import ugettext_lazy as _ |
4 | 4 | |
5 | 5 | from django import forms |
6 | 6 | from django.core.urlresolvers import reverse_lazy |
7 | - | |
7 | +from amadeus import settings | |
8 | 8 | from django.contrib import messages |
9 | - | |
9 | +from os.path import join | |
10 | 10 | import django.views.generic as generic |
11 | 11 | from mural.models import SubjectPost, Comment, MuralVisualizations |
12 | 12 | from django.db.models import Q |
... | ... | @@ -20,6 +20,7 @@ from collections import OrderedDict |
20 | 20 | from django.forms import formset_factory |
21 | 21 | from .models import ReportCSV, ReportXLS |
22 | 22 | import pandas as pd |
23 | +from io import BytesIO | |
23 | 24 | |
24 | 25 | class ReportView(LoginRequiredMixin, generic.FormView): |
25 | 26 | template_name = "reports/create.html" |
... | ... | @@ -133,11 +134,13 @@ class ViewReportView(LoginRequiredMixin, generic.TemplateView): |
133 | 134 | context['end_date'] = params_data['end_date'] |
134 | 135 | context['subject'] = subject |
135 | 136 | |
137 | + #I used getlist method so it can get more than one tag and one resource class_name | |
136 | 138 | resources = params_data.getlist('resource') |
137 | 139 | tags = params_data.getlist('tag') |
140 | + | |
138 | 141 | self.from_mural = params_data['from_mural'] |
139 | - #I used getlist method so it can get more than one tag and one resource class_name | |
140 | - context['data'], context['header'] = self.get_mural_data(subject, params_data['init_date'], params_data['end_date'], | |
142 | + | |
143 | + context['data'], context['header'] = self.get_mural_data(subject, context['topic_name'], params_data['init_date'], params_data['end_date'], | |
141 | 144 | resources, tags ) |
142 | 145 | |
143 | 146 | |
... | ... | @@ -154,19 +157,32 @@ class ViewReportView(LoginRequiredMixin, generic.TemplateView): |
154 | 157 | report.save() |
155 | 158 | |
156 | 159 | #for excel files |
157 | - """ if ReportXLS.objects.filter(user= self.request.user).count() > 0: | |
160 | + if ReportXLS.objects.filter(user= self.request.user).count() > 0: | |
158 | 161 | report = ReportXLS.objects.get(user=self.request.user) |
159 | 162 | report.delete() |
160 | 163 | |
161 | - df.drop(df.columns[[0]], axis=1, inplace=True) | |
162 | - writer = pd.ExcelWriter('pandas_simple.xlsx') | |
163 | - report = ReportXLS(user= self.request.user, xls_data = df.to_excel(writer)) | |
164 | - report.save()""" | |
165 | - | |
164 | + path = join(settings.MEDIA_ROOT, 'files' , 'report'+str(self.request.user.id)+'.xls') | |
165 | + writer = pd.ExcelWriter(path) | |
166 | + df.to_excel(writer, sheet_name='first_sheet') | |
167 | + writer.save() | |
168 | + report = ReportXLS(user= self.request.user ) | |
169 | + report.xls_data.name = path | |
170 | + report.save() | |
166 | 171 | |
167 | 172 | return context |
168 | 173 | |
169 | - def get_mural_data(self, subject, init_date, end_date, resources_id, tags_id): | |
174 | + | |
175 | + def get_mural_data(self, subject, topics_query, init_date, end_date, resources_type_names, tags_id): | |
176 | + """ | |
177 | + | |
178 | + Process all the data to be brough by the report | |
179 | + Subject: subject where the report is being created | |
180 | + topics_query: it's either one of the topics or all of them | |
181 | + init_date: When the reports filter of dates stars | |
182 | + end_date: When the reports filter of dates end | |
183 | + resources_type_names: resources subclasses name that were selected | |
184 | + tags_id = ID of tag objects that were selected | |
185 | + """ | |
170 | 186 | data = {} |
171 | 187 | students = subject.students.all() |
172 | 188 | formats = ["%d/%m/%Y", "%m/%d/%Y", "%Y-%m-%d"] #so it accepts english and portuguese date formats |
... | ... | @@ -177,7 +193,10 @@ class ViewReportView(LoginRequiredMixin, generic.TemplateView): |
177 | 193 | |
178 | 194 | except ValueError: |
179 | 195 | pass |
180 | - | |
196 | + if topics_query == _("All"): | |
197 | + topics = subject.topic_subject.all() | |
198 | + else: | |
199 | + topics = Topic.objects.get(id=topics_query) | |
181 | 200 | header = ['User'] |
182 | 201 | |
183 | 202 | #I use this so the system can gather data up to end_date 11h59 p.m. |
... | ... | @@ -186,9 +205,9 @@ class ViewReportView(LoginRequiredMixin, generic.TemplateView): |
186 | 205 | |
187 | 206 | #For each student in the subject |
188 | 207 | for student in students: |
189 | - data[student] = [] | |
208 | + data[student.id] = [] | |
190 | 209 | |
191 | - data[student].append(student.social_name) | |
210 | + data[student.id].append(student.social_name) | |
192 | 211 | |
193 | 212 | interactions = OrderedDict() |
194 | 213 | |
... | ... | @@ -240,26 +259,26 @@ class ViewReportView(LoginRequiredMixin, generic.TemplateView): |
240 | 259 | |
241 | 260 | |
242 | 261 | #VAR08 through VAR_019 of documenttation: |
243 | - if len(resources_id) > 0: | |
244 | - resources_data = self.get_resources_and_tags_data(resources_id, tags_id, student, subject, init_date, end_date) | |
262 | + if len(resources_type_names) > 0: | |
263 | + resources_data = self.get_resources_and_tags_data(resources_type_names, tags_id, student, subject, topics, init_date, end_date) | |
245 | 264 | for key, value in resources_data.items(): |
246 | 265 | interactions[key] = value |
247 | 266 | |
248 | 267 | |
249 | 268 | #VAR20 - number of access to mural between 6 a.m to 12a.m. |
250 | 269 | interactions[_('Number of access to mural between 6 a.m to 12a.m. .')] = Log.objects.filter(action="access", resource="subject", |
251 | - user_id= student.id, context__contains = {'subject_id' : subject.id}, datetime__hour__range = (5, 11)).count() | |
270 | + user_id= student.id, context__contains = {'subject_id' : subject.id}, datetime__hour__range = (5, 11), datetime__range=(init_date,end_date)).count() | |
252 | 271 | |
253 | 272 | #VAR21 - number of access to mural between 0 p.m to 6p.m. |
254 | 273 | interactions[_('Number of access to mural between 0 p.m to 6p.m. .')] = Log.objects.filter(action="access", resource="subject", |
255 | - user_id= student.id, context__contains = {'subject_id' : subject.id}, datetime__hour__range = (11, 17)).count() | |
274 | + user_id= student.id, context__contains = {'subject_id' : subject.id}, datetime__hour__range = (11, 17), datetime__range=(init_date,end_date)).count() | |
256 | 275 | #VAR22 |
257 | 276 | interactions[_('Number of access to mural between 6 p.m to 12p.m. .')] = Log.objects.filter(action="access", resource="subject", |
258 | - user_id= student.id, context__contains = {'subject_id' : subject.id}, datetime__hour__range = (17, 23)).count() | |
277 | + user_id= student.id, context__contains = {'subject_id' : subject.id}, datetime__hour__range = (17, 23), datetime__range=(init_date,end_date)).count() | |
259 | 278 | |
260 | 279 | #VAR23 |
261 | 280 | interactions[_('Number of access to mural between 0 a.m to 6a.m. .')] = Log.objects.filter(action="access", resource="subject", |
262 | - user_id= student.id, context__contains = {'subject_id' : subject.id}, datetime__hour__range = (23, 5)).count() | |
281 | + user_id= student.id, context__contains = {'subject_id' : subject.id}, datetime__hour__range = (23, 5), datetime__range=(init_date,end_date)).count() | |
263 | 282 | |
264 | 283 | #VAR24 through 30 |
265 | 284 | day_numbers = [0, 1, 2, 3, 4, 5, 6] |
... | ... | @@ -267,7 +286,7 @@ class ViewReportView(LoginRequiredMixin, generic.TemplateView): |
267 | 286 | distinct_days = 0 |
268 | 287 | for day_num in day_numbers: |
269 | 288 | interactions[_('Number of access to the subject on ')+ day_names[day_num]] = Log.objects.filter(action="access", resource="subject", |
270 | - user_id= student.id, context__contains = {'subject_id' : subject.id}, datetime__week_day = day_num).count() | |
289 | + user_id= student.id, context__contains = {'subject_id' : subject.id}, datetime__week_day = day_num, datetime__range = (init_date, end_date)).count() | |
271 | 290 | #to save the distinct days the user has accessed |
272 | 291 | if interactions[_('Number of access to the subject on ')+ day_names[day_num]] > 0: |
273 | 292 | distinct_days += 1 |
... | ... | @@ -276,25 +295,39 @@ class ViewReportView(LoginRequiredMixin, generic.TemplateView): |
276 | 295 | interactions[_("Class")] = "" |
277 | 296 | interactions[_("Performance")] = "" |
278 | 297 | for value in interactions.values(): |
279 | - data[student].append(value) | |
298 | + data[student.id].append(value) | |
280 | 299 | |
281 | 300 | |
282 | 301 | for key in interactions.keys(): |
283 | 302 | header.append(key) |
284 | 303 | return data, header |
285 | 304 | |
286 | - def get_resources_and_tags_data(self, resources_types, tags, student, subject, init_date, end_date): | |
305 | + def get_resources_and_tags_data(self, resources_types, tags, student, subject, topics, init_date, end_date): | |
287 | 306 | data = OrderedDict() |
288 | - | |
307 | + | |
289 | 308 | for i in range(len(resources_types)): |
290 | 309 | |
291 | - resources = Resource.objects.select_related(resources_types[i].lower()).filter(tags__in = tags, topic__in=subject.topic_subject.all()) | |
310 | + if isinstance(topics,Topic): | |
311 | + resources = Resource.objects.select_related(resources_types[i].lower()).filter(tags__in = tags, topic=topics) | |
312 | + else: | |
313 | + resources = Resource.objects.select_related(resources_types[i].lower()).filter(tags__in = tags, topic__in=topics) | |
292 | 314 | distinct_resources = 0 |
293 | 315 | total_count = 0 |
316 | + | |
294 | 317 | for resource in resources: |
295 | - count = Log.objects.filter(action="view", resource=resources_types[i].lower(), | |
296 | - user_id = student.id, context__contains = {'subject_id': subject.id, | |
297 | - resources_types[i].lower()+'_id': resource.id}, datetime__range=(init_date, end_date)).count() | |
318 | + if isinstance(topics,Topic): | |
319 | + #or it selected only one topic to work with | |
320 | + count = Log.objects.filter(action="view", resource=resources_types[i].lower(), | |
321 | + user_id = student.id, context__contains = {'subject_id': subject.id, | |
322 | + resources_types[i].lower()+'_id': resource.id, 'topic_id': topics.id}, datetime__range=(init_date, end_date)).count() | |
323 | + | |
324 | + else: | |
325 | + #or the user selected all | |
326 | + | |
327 | + count = Log.objects.filter(action="view", resource=resources_types[i].lower(), | |
328 | + user_id = student.id, context__contains = {'subject_id': subject.id, | |
329 | + resources_types[i].lower()+'_id': resource.id}, datetime__range=(init_date, end_date)).count() | |
330 | + | |
298 | 331 | if count > 0: |
299 | 332 | distinct_resources += 1 |
300 | 333 | total_count += count |
... | ... | @@ -366,7 +399,7 @@ def get_tags(request): |
366 | 399 | |
367 | 400 | #adding empty tag for the purpose of giving the user this option for adicional behavior |
368 | 401 | tags = list(tags) |
369 | - tags.append(Tag(name="")) | |
402 | + tags.append(Tag(name=" ")) | |
370 | 403 | data['tags'] = [ {'id':tag.id, 'name':tag.name} for tag in tags] |
371 | 404 | return JsonResponse(data) |
372 | 405 | |
... | ... | @@ -377,4 +410,12 @@ def download_report_csv(request): |
377 | 410 | response = HttpResponse(report.csv_data,content_type='text/csv') |
378 | 411 | response['Content-Disposition'] = 'attachment; filename="report.csv"' |
379 | 412 | |
413 | + return response | |
414 | + | |
415 | +def download_report_xls(request): | |
416 | + report = ReportXLS.objects.get(user= request.user) | |
417 | + | |
418 | + response = HttpResponse(report.xls_data,content_type='application/ms-excel') | |
419 | + response['Content-Disposition'] = 'attachment; filename="report.xls"' | |
420 | + | |
380 | 421 | return response |
381 | 422 | \ No newline at end of file | ... | ... |