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.

148
web/chart_views.py Normal file
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')

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):

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'),
]

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