From 067a34023597b6a23302a6fe4439025975737293 Mon Sep 17 00:00:00 2001 From: adityacp Date: Thu, 13 Aug 2020 16:44:13 +0530 Subject: Add pandas to the requirements --- requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 622c429..cc9dfd7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,4 +2,5 @@ Django==3.0.7 coverage pyaml django-recurrence -python-decouple==3.3 \ No newline at end of file +python-decouple==3.3 +pandas -- cgit From 3e970943db3385eab32bdbc7f85fb69cf4450552 Mon Sep 17 00:00:00 2001 From: adityacp Date: Thu, 13 Aug 2020 16:45:36 +0530 Subject: Fix login_url in settings and statistics in urls --- workshop_portal/settings.py | 2 +- workshop_portal/urls.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/workshop_portal/settings.py b/workshop_portal/settings.py index 78f0358..67f7f12 100644 --- a/workshop_portal/settings.py +++ b/workshop_portal/settings.py @@ -134,7 +134,7 @@ STATIC_URL = '/static/' STATIC_ROOT = 'workshop_app/static/' -LOGIN_URL = '/login/' +LOGIN_URL = '/workshop/login/' MEDIA_URL = '/data/' diff --git a/workshop_portal/urls.py b/workshop_portal/urls.py index 45f1407..59a7431 100644 --- a/workshop_portal/urls.py +++ b/workshop_portal/urls.py @@ -26,6 +26,7 @@ urlpatterns = [ url(r'^workshop/', include('workshop_app.urls')), url(r'^reset/', include('django.contrib.auth.urls')), url(r'^page/', include('cms.urls')), + url(r'^statistics/', include('statistics_app.urls')), ] urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) -- cgit From 8e7c9aeadcae850155e17a0323b1079e0e642010 Mon Sep 17 00:00:00 2001 From: adityacp Date: Thu, 13 Aug 2020 16:47:59 +0530 Subject: Multiple Changes - Fix admin csv download for profile and workshops - Add model manager to get workshops by state and type - Add chartjs, jquery-ui in base.html --- workshop_app/admin.py | 45 ++++++++++++--------------- workshop_app/models.py | 36 ++++++++++++++++++++- workshop_app/static/workshop_app/css/base.css | 3 +- workshop_app/templates/workshop_app/base.html | 22 +++++++++++++ 4 files changed, 79 insertions(+), 27 deletions(-) diff --git a/workshop_app/admin.py b/workshop_app/admin.py index 988351f..d236c39 100644 --- a/workshop_app/admin.py +++ b/workshop_app/admin.py @@ -1,4 +1,4 @@ -import csv +import pandas as pd from django.contrib import admin from django.http import HttpResponse @@ -23,21 +23,15 @@ class ProfileAdmin(admin.ModelAdmin): actions = ['download_csv'] def download_csv(self, request, queryset): - openfile = string_io() + data = queryset.values( + "title", "user__first_name", "user__last_name", + "user__email", "institute", "location", "department", + "phone_number" + ) + df = pd.DataFrame(data) response = HttpResponse(content_type='text/csv') - response['Content-Disposition'] = 'attachment;filename=profile_data.csv' - writer = csv.writer(response) - writer.writerow(['email_id', 'title', 'username', 'first_name', 'last_name', - 'institute', 'location', 'department', - 'phone_number', 'position']) - for q in queryset: - writer.writerow([q.user.email, q.title, q.user, q.user.first_name, - q.user.last_name, q.institute, - q.location, q.department, q.phone_number, - q.position]) - - openfile.seek(0) - response.write(openfile.read()) + response['Content-Disposition'] = f'attachment; filename=profile.csv' + output_file = df.to_csv(response, index=False) return response download_csv.short_description = "Download CSV file for selected stats." @@ -49,17 +43,18 @@ class WorkshopAdmin(admin.ModelAdmin): actions = ['download_csv'] def download_csv(self, request, queryset): - openfile = string_io() + data = queryset.values( + "workshop_type__name", "date", "coordinator__first_name", + "coordinator__last_name", "instructor__first_name", + "instructor__last_name", "status" + ) + df = pd.DataFrame(data) + df.status.replace( + [0, 1, 2], ['Pending', 'Success', 'Reject'], inplace=True + ) response = HttpResponse(content_type='text/csv') - response['Content-Disposition'] = 'attachment;filename=workshop_data.csv' - writer = csv.writer(response) - writer.writerow(['workshop_type', 'date', 'instructor', 'coordinator', 'status']) - - for q in queryset: - writer.writerow([q.title, q.date, q.instructor, q.coordinator, q.status]) - - openfile.seek(0) - response.write(openfile.read()) + response['Content-Disposition'] = f'attachment; filename=workshops.csv' + output_file = df.to_csv(response, index=False) return response download_csv.short_description = "Download CSV file for selected stats." diff --git a/workshop_app/models.py b/workshop_app/models.py index 62d10b5..48856fd 100644 --- a/workshop_app/models.py +++ b/workshop_app/models.py @@ -1,5 +1,6 @@ import os import uuid +import pandas as pd from django.contrib.auth.models import User from django.core.validators import RegexValidator @@ -44,6 +45,7 @@ source = ( ) states = ( + ("", "---------"), ("IN-AP", "Andhra Pradesh"), ("IN-AR", "Arunachal Pradesh"), ("IN-AS", "Assam"), @@ -85,7 +87,7 @@ states = ( def has_profile(user): """ check if user has profile """ - return True if hasattr(user, 'profile') else False + return hasattr(user, 'profile') def attachments(instance, filename): @@ -155,6 +157,34 @@ class AttachmentFile(models.Model): workshop_type = models.ForeignKey(WorkshopType, on_delete=models.CASCADE) +class WorkshopManager(models.Manager): + + def get_workshops_by_state(self, workshops): + w = workshops.values_list("coordinator__profile__state", flat=True) + states_map = dict(states) + df = pd.DataFrame(w) + data_states, data_counts = [], [] + if not df.empty: + grouped_data = df.value_counts().to_dict() + for state, count in grouped_data.items(): + state_name = state[0] + data_states.append(states_map[state_name]) + data_counts.append(count) + return data_states, data_counts + + def get_workshops_by_type(self, workshops): + w = workshops.values_list("workshop_type__name", flat=True) + df = pd.DataFrame(w) + data_wstypes, data_counts = [], [] + if not df.empty: + grouped_data = df.value_counts().to_dict() + for ws, count in grouped_data.items(): + ws_name = ws[0] + data_wstypes.append(ws_name) + data_counts.append(count) + return data_wstypes, data_counts + + class Workshop(models.Model): """ Contains details of workshops @@ -179,6 +209,8 @@ class Workshop(models.Model): help_text="I accept the terms and conditions" ) + objects = WorkshopManager() + def __str__(self): return f"{self.workshop_type} on {self.date} by {self.coordinator}" @@ -187,6 +219,8 @@ class Workshop(models.Model): return choice.get(self.status) + + class Testimonial(models.Model): """ Contains Testimonals of Workshops diff --git a/workshop_app/static/workshop_app/css/base.css b/workshop_app/static/workshop_app/css/base.css index 31f8da5..e8dd4ed 100644 --- a/workshop_app/static/workshop_app/css/base.css +++ b/workshop_app/static/workshop_app/css/base.css @@ -2,7 +2,7 @@ * Footer Styles */ .navbar { - z-index: 1000; + z-index: 1000; } .footer { position: fixed; @@ -11,6 +11,7 @@ background-color: #61615F; color: white; text-align: center; + z-index: 100; } .base-content { padding-top: 5em; diff --git a/workshop_app/templates/workshop_app/base.html b/workshop_app/templates/workshop_app/base.html index 7535f6a..ba968ba 100644 --- a/workshop_app/templates/workshop_app/base.html +++ b/workshop_app/templates/workshop_app/base.html @@ -14,6 +14,8 @@ + + {% block extra-dependencies %} @@ -24,6 +26,7 @@ + {% block extra-custom-scripts %} {% endblock %} @@ -43,8 +46,27 @@