This commit is contained in:
2018-12-27 04:30:12 +04:00
parent 48b4c9bbfe
commit 273afd18d0
24 changed files with 374 additions and 116 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+148
View File
@@ -0,0 +1,148 @@
import io
from collections.__init__ import defaultdict
from datetime import timedelta
import numpy as np
from django.http import HttpResponse
from django.views.generic import DetailView
from web.models import User, ActivityLog, Activity
class UserChartsPie(DetailView):
model = User
pk_url_kwarg = 'user_id'
def render_to_response(self, context, **response_kwargs):
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(6, 6), dpi=100)
ax = fig.add_subplot(111)
total_time = defaultdict(float)
logs = ActivityLog.objects.filter(user=self.object).all()
for log in logs:
total_time[str(log.activity)] += (log.end_time - log.start_time).total_seconds()
sectors = sorted(list(total_time.items()), key=lambda x: x[1])
ax.pie(x=[i[1] for i in sectors], labels=[i[0] for i in sectors])
buf = io.BytesIO()
fig.savefig(buf, format='png')
b = buf.getvalue()
return HttpResponse(b, content_type='image/png')
class UserChartsActivityAll(DetailView):
model = User
pk_url_kwarg = 'user_id'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['activity'] = Activity.objects.filter(id=self.kwargs['activity_id']).first()
return context
def bar_chart(self, plt, ax, logs, day_l, day_r, day_count, days):
day_seconds = np.zeros(day_count)
for log in logs:
for i, day in enumerate(days):
l = max(log.start_time, day)
r = min(log.end_time, day + timedelta(days=1))
if r > l:
day_seconds[i] += (r - l).total_seconds()
day_hours = day_seconds / timedelta(hours=1).total_seconds()
ax.bar(days, day_hours)
plt.xticks(days, [f'{i:%m-%d}' for i in days], rotation=60)
plt.ylabel('кол-во часов')
def tracker_chart(self, plt, ax, logs, day_l, day_r, day_count, days):
ys = []
widths = []
lefts = []
for log in logs:
for i, day in enumerate(days):
l = max(log.start_time, day)
r = min(log.end_time, day + timedelta(days=1))
if r > l:
ys.append(day)
widths.append((r - l) / timedelta(hours=1))
lefts.append((l - day) / timedelta(hours=1))
ax.barh(y=ys, width=widths, left=lefts, zorder=2)
plt.xlim(0, 24)
plt.xticks(range(24), [f'{i:02d}:00' for i in range(24)])
plt.yticks(days, [f'{i:%m-%d}' for i in days])
plt.grid(True, zorder=1)
def render_to_response(self, context, **response_kwargs):
logs = list(ActivityLog.objects.filter(user=self.object, activity=context['activity']).order_by('start_time').all())
day_r = logs[-1].end_time.replace(hour=0, minute=0, second=0, microsecond=0)
day_l = max(
logs[0].start_time.replace(hour=0, minute=0, second=0, microsecond=0),
day_r - timedelta(days=14)
)
day_count = (day_r - day_l) // timedelta(days=1) + 1
days = [day_l + timedelta(days=1) * i for i in range(day_count)]
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(16, 12), dpi=100)
ax = fig.add_subplot(211)
self.bar_chart(plt, ax, logs, day_l, day_r, day_count, days)
ax = fig.add_subplot(212)
self.tracker_chart(plt, ax, logs, day_l, day_r, day_count, days)
buf = io.BytesIO()
fig.savefig(buf, format='png')
b = buf.getvalue()
return HttpResponse(b, content_type='image/png')
class UserActivityChartsTracker(DetailView):
model = User
pk_url_kwarg = 'user_id'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['activity'] = Activity.objects.filter(id=self.kwargs['activity_id']).first()
return context
def render_to_response(self, context, **response_kwargs):
print('start_tracker')
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(16, 6), dpi=100)
ax = fig.add_subplot(111)
logs = list(ActivityLog.objects.filter(user=self.object, activity=context['activity']).order_by('start_time').all())
day_r = logs[-1].end_time.replace(hour=0, minute=0, second=0, microsecond=0)
day_l = max(
logs[0].start_time.replace(hour=0, minute=0, second=0, microsecond=0),
day_r - timedelta(days=14)
)
day_count = (day_r - day_l) // timedelta(days=1) + 1
days = [day_l + timedelta(days=1) * i for i in range(day_count)]
buf = io.BytesIO()
fig.savefig(buf, format='png')
b = buf.getvalue()
return HttpResponse(b, content_type='image/png')
Binary file not shown.
+6 -6
View File
@@ -3,8 +3,8 @@ from django.db import models
class User(models.Model):
name = models.TextField()
email = models.TextField()
name = models.TextField(verbose_name='Имя')
email = models.TextField(verbose_name='Почта')
def __str__(self):
return f'{self.name}'
@@ -18,11 +18,11 @@ class Activity(models.Model):
class ActivityLog(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
activity = models.ForeignKey(Activity, on_delete=models.CASCADE)
user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name='Пользователь')
activity = models.ForeignKey(Activity, on_delete=models.CASCADE, verbose_name='Тип активности')
start_time = models.DateTimeField()
end_time = models.DateTimeField()
start_time = models.DateTimeField(verbose_name='Момент начала')
end_time = models.DateTimeField(verbose_name='Момент окончания')
logged_at = models.DateTimeField(auto_now_add=True)
def clean(self):
+10
View File
@@ -1,5 +1,6 @@
from django.urls import path
from web import chart_views
from web import views
urlpatterns = [
@@ -16,4 +17,13 @@ urlpatterns = [
views.ActivityLogUpdateView.as_view(), name='activity_log_update'),
path('users/<int:user_id>/activity_log/<int:activity_log_id>/delete',
views.ActivityLogDeleteView.as_view(), name='activity_log_delete'),
path('users/<int:user_id>/charts/pie',
chart_views.UserChartsPie.as_view(), name='user_charts_pie'),
path('users/<int:user_id>/charts/activity/<int:activity_id>',
views.UserChartsActivity.as_view(), name='user_charts_activity'),
path('users/<int:user_id>/charts/activity/<int:activity_id>/all',
chart_views.UserChartsActivityAll.as_view(), name='user_charts_activity_all'),
# path('users/<int:user_id>/charts/activity/<int:activity_id>/tracker',
# chart_views.UserActivityChartsTracker.as_view(), name='user_charts_activity_tracker'),
]
+17 -3
View File
@@ -1,7 +1,7 @@
from django.urls import reverse_lazy, reverse
from django.views.generic import ListView, DetailView, CreateView, UpdateView, DeleteView
from django.urls import reverse, reverse_lazy
from django.views.generic import CreateView, DeleteView, DetailView, ListView, UpdateView
from web.models import Activity, User, ActivityLog
from web.models import ActivityLog, User, Activity
class UserListView(ListView):
@@ -22,6 +22,7 @@ class UserDetailView(DetailView):
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['activity_logs'] = ActivityLog.objects.filter(user=self.object).order_by('start_time')
context['activities'] = set(i.activity for i in ActivityLog.objects.filter(user=self.object))
return context
@@ -54,3 +55,16 @@ class ActivityLogDeleteView(DeleteView):
return reverse('user', kwargs={
'user_id': self.object.user.id,
})
class UserChartsActivity(DetailView):
model = User
pk_url_kwarg = 'user_id'
template_name_suffix = '_activity_charts'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['activity'] = Activity.objects.filter(id=self.kwargs['activity_id']).first()
return context