update: new query method to calculate workload, the sub_executor_count field in database can be remove now.

This commit is contained in:
raiots 2021-08-22 23:24:47 +08:00
parent 81c2e817d1
commit 3283478b42
5 changed files with 281 additions and 173 deletions

View File

@ -1,6 +1,5 @@
from django.db import connection
def my_annotate():
query1 = '''
CREATE TEMPORARY TABLE work_cal AS

View File

@ -1,3 +1,155 @@
from django.core import serializers
from django.core.serializers.json import DjangoJSONEncoder
from django.http import HttpResponse, JsonResponse
from django.shortcuts import render
from django.test import TestCase
# Create your tests here.
from django.db.models import Sum, F, FloatField, Count, Q
from django.utils import timezone
from django.views import View
from apps.users.models import User
from apps.tasks.models import Todo
import pandas as pd
from collections import defaultdict, Counter
from copy import deepcopy
class TestView(View):
def get(self, request, year=2021, month=7):
# sub_credit = User.objects.filter(department=request.user.department).annotate(
# pre_credit=Sum(
# (F('sub_executor__predict_work') * (1 - F('sub_executor__evaluate_factor')) / F(
# 'sub_executor__sub_executor_count')
# ),
# filter=Q(sub_executor__deadline__year=year, sub_executor__deadline__month=month),
# output_field=FloatField()
# ),
# real_credit=Sum(
# (F('sub_executor__real_work') * (1 - F('sub_executor__evaluate_factor')) / F(
# 'sub_executor__sub_executor_count')
# ),
# filter=Q(sub_executor__deadline__year=year, sub_executor__deadline__month=month),
# output_field=FloatField()
# )
# ).values('id', 'real_name', 'pre_credit', 'real_credit')
# sub_credit = [entry for entry in sub_credit]
# 建立username和真实姓名的对应字典并在工作量计算完成后插入结果集
user_info = User.objects.filter(department=request.user.department)\
.values_list('username', 'real_name')
user_name = {}
for user in user_info:
user_name[user[0]] = user[1]
# print(user_name)
# 以用户表查询,按用户列出所参与承办、协办任务,并在之后按用户名分组合并。
main_credit = User.objects.filter(department=request.user.department)\
.annotate(main_count=Count('main_executor'))\
.order_by('username')\
.values('username', 'main_executor', 'main_executor__predict_work', 'main_executor__real_work',
'main_executor__evaluate_factor', 'main_count') # 这里的annotate不知会不会有问题
sub_count = Todo.objects.filter(sub_executor__department=request.user.department) \
.annotate(sub_count=Count('sub_executor')).values('id', 'sub_count')
sub_credit = User.objects.filter(department=request.user.department) \
.order_by('username') \
.values('username', 'real_name', 'sub_executor', 'sub_executor__predict_work', 'sub_executor__real_work',
'sub_executor__evaluate_factor')
# 构建工作包id对应协办人人数的字典
sub_exe_count = {}
for i in sub_count:
key = i['id']
value = i['sub_count']
sub_exe_count[key] = value
# print(sub_exe_count)
# 计算每个承办任务的预计、实际工作量,并插入字典
for i in main_credit:
i['main_pre_cal'] = i['main_executor__predict_work'] * i['main_executor__evaluate_factor']
i['main_real_cal'] = i['main_executor__real_work'] * i['main_executor__evaluate_factor']
# print(i)
# print(str(i['sub_executor']))
# 将协办任务对应的人数插入,计算每个协办任务的预计、实际工作量,并插入字典
for i in sub_credit:
sub_todo_id = i['sub_executor']
i['sub_exe_count'] = sub_exe_count[sub_todo_id]
i['sub_pre_cal'] = i['sub_executor__predict_work'] * (1 - i['sub_executor__evaluate_factor']) / i['sub_exe_count']
i['sub_real_cal'] = i['sub_executor__real_work'] * (1 - i['sub_executor__evaluate_factor']) / i['sub_exe_count']
i['sub_count'] = 1 # 用于帮助累加程序计算每个用户的协办任务数量, sub_exe_count会返回此协办任务的协办人数在累加时导致计算错误
# print(i)
# print(str(i['sub_executor']))
# 用于按用户名合并任务会对指定字段进行累加类似GROUP BY(SUM),但会丢失无需计算的部分,因此之前需要单独构建姓名字典
def solve(dataset, group_by_key, sum_value_keys):
dic = defaultdict(Counter)
for item in dataset:
key = item[group_by_key]
vals = {k: item[k] for k in sum_value_keys}
dic[key].update(vals)
return dic
main_credit = solve(main_credit, 'username', ['main_pre_cal', 'main_real_cal', 'main_count'])
main_credit = dict(main_credit)
sub_credit = solve(sub_credit, 'username', ['sub_pre_cal', 'sub_real_cal', 'sub_count'])
sub_credit = dict(sub_credit)
total_credit = deepcopy(main_credit)
# 按用户名合并承办与协办任务字典
for key in sub_credit.keys():
if key in total_credit:
total_credit[key].update(sub_credit[key])
else:
total_credit[key] = sub_credit[key]
# print(total_credit['admin']['sub_pre_cal'])
# 根据字典内容,计算总工作量
for key, value in total_credit.items():
# print(value)
value['pre_cal'] = value['sub_pre_cal'] + value['main_pre_cal']
value['real_cal'] = value['sub_real_cal'] + value['main_real_cal']
value['real_name'] = user_name[key]
# total_credit = dict(main_credit.items() + sub_credit.items())
# for value in sub_credit.values():
# dict(value)
# print(sub_credit)
#
# new_pair = {}
# for doc, tab in sub_credit.items():
# new_pair[doc] = {}
# for word, freq in tab.items():
# new_pair[doc][word] = freq
# print(new_pair)
# return HttpResponse(str(main_credit)+str(sub_credit))
current_user = total_credit[request.user.username]
print(current_user)
# 累加该部门各个用户的工作量,计算部门工作量
department_cal = {}
temp_pre = []
depart_pre, depart_real, depart_count = 0, 0, 0
for username, value in total_credit.items():
print(username)
print(value['pre_cal'])
depart_pre = depart_pre + value['pre_cal']
depart_real = depart_real + value['real_cal']
depart_count = depart_count + value['main_count']
temp_pre.append(value['pre_cal'])
department_cal['pre_cal'] = depart_pre
department_cal['real_cal'] = depart_real
department_cal['depart_count'] = depart_count
department_cal['pre_avg'] = department_cal['pre_cal'] / len(total_credit)
department_cal['real_avg'] = department_cal['real_cal'] / len(total_credit)
# 为页面提供日期信息
date = str(year) + '' + str(month) + ''
# return HttpResponse(str(total_credit) + '\n' + str(department_cal))
context = {'date': date, 'users_data': total_credit, 'department_cal': department_cal,
'current_user': current_user}
return render(request, 'tasks/index.html', context)

View File

@ -1,10 +1,11 @@
from django.urls import path
from apps.tasks import views
from apps.tasks import views, tests
app_name = 'tasks'
urlpatterns = [
path('', views.IndexView.as_view(), name='index'),
path('<int:year>/<int:month>/', views.IndexView.as_view(), name='index_month'),
path('test/', tests.TestView.as_view(), name='index'),
path('login/', views.UserLoginView.as_view(), name='login'),
path('logout/', views.UserLogoutView.as_view(), name='logout'),
path('todolist/', views.TodoListView.as_view(), name='todolist'),

View File

@ -1,4 +1,5 @@
import re
from collections import defaultdict, Counter
from copy import deepcopy
from django.contrib import auth, messages
@ -28,173 +29,128 @@ class IndexView(View):
@method_decorator(login_required)
def get(self, request, year=timezone.now().year, month=timezone.now().month):
raw = my_query.my_annotate()
# return HttpResponse(raw)
basic_users = User.objects.filter(department=request.user.department).annotate(
main_executor_count=Count('main_executor',
filter=Q(main_executor__deadline__year=year, main_executor__deadline__month=month)
, distinct=True),
sub_executor_count=Count('sub_executor',
filter=Q(sub_executor__deadline__year=year, sub_executor__deadline__month=month),
distinct=True)
).values('id', 'real_name', 'main_executor_count', 'sub_executor_count')
# 建立username和真实姓名的对应字典并在工作量计算完成后插入结果集
user_info = User.objects.filter(department=request.user.department)\
.values_list('username', 'real_name')
user_name = {}
for user in user_info:
user_name[user[0]] = user[1]
# print(user_name)
basic_users = [entry for entry in basic_users]
basic_user_cal = {}
for i in basic_users:
basic_user_cal.update({i['id']: i})
print(basic_user_cal)
# 以用户表查询,按用户列出所参与承办、协办任务,并在之后按用户名分组合并。
main_credit = User.objects.filter(department=request.user.department,
main_executor__deadline__year=year, main_executor__deadline__month=month)\
.annotate(main_count=Count('main_executor'))\
.order_by('username')\
.values('username', 'main_executor', 'main_executor__predict_work', 'main_executor__real_work',
'main_executor__evaluate_factor', 'main_count') # 这里的annotate不知会不会有问题
current_user = User.objects.filter(username=request.user.username).annotate(
main_executor_count=Count('main_executor',
filter=Q(main_executor__deadline__year=year, main_executor__deadline__month=month)
, distinct=True),
sub_executor_count=Count('sub_executor',
filter=Q(sub_executor__deadline__year=year, sub_executor__deadline__month=month),
distinct=True),
pre_credit=Sum(
F('main_executor__predict_work') * F('main_executor__evaluate_factor'),
filter=Q(main_executor__deadline__year=year, main_executor__deadline__month=month),
distinct=True,
output_field=FloatField()
),
real_credit=Sum(
F('main_executor__real_work') * F('main_executor__evaluate_factor'),
filter=Q(main_executor__deadline__year=year, main_executor__deadline__month=month),
distinct=True,
output_field=FloatField()
)
)
sub_count = Todo.objects.filter(sub_executor__department=request.user.department,
deadline__year=year, deadline__month=month) \
.annotate(sub_count=Count('sub_executor')).values('id', 'sub_count')
sub_credit = User.objects.filter(department=request.user.department,
sub_executor__deadline__year=year, sub_executor__deadline__month=month) \
.order_by('username') \
.values('username', 'real_name', 'sub_executor', 'sub_executor__predict_work', 'sub_executor__real_work',
'sub_executor__evaluate_factor')
department_cal = Todo.objects.filter(main_executor__department=request.user.department,
deadline__year=year, deadline__month=month).aggregate(count=Count('id'),
pre_total=Sum('predict_work'), real_total=Sum('real_work'), pre_avg=Sum('predict_work'), real_avg=Sum('real_work')).values()
keys = ['count', 'pre_total', 'real_total', 'pre_avg', 'real_avg']
temp = []
for values in department_cal:
print(values)
temp.append(values)
#TODO 解决部门tem无数据报错问题
try:
tem = [float(tem) for tem in temp]
whole = dict(zip(keys, tem))
pre_avg = {'pre_avg': float(whole['pre_avg'])/request.user.department.get_user_number}
real_avg = {'real_avg': float(whole['real_avg']) / request.user.department.get_user_number}
whole.update(pre_avg)
whole.update(real_avg)
except:
whole = {}
print('无数据')
# print(whole)
# 构建工作包id对应协办人人数的字典
sub_exe_count = {}
for i in sub_count:
key = i['id']
value = i['sub_count']
sub_exe_count[key] = value
# print(sub_exe_count)
# 计算每个承办任务的预计、实际工作量,并插入字典
for i in main_credit:
i['main_pre_cal'] = i['main_executor__predict_work'] * i['main_executor__evaluate_factor']
i['main_real_cal'] = i['main_executor__real_work'] * i['main_executor__evaluate_factor']
# print(i)
# print(str(i['sub_executor']))
# 将协办任务对应的人数插入,计算每个协办任务的预计、实际工作量,并插入字典
for i in sub_credit:
sub_todo_id = i['sub_executor']
i['sub_exe_count'] = sub_exe_count[sub_todo_id]
i['sub_pre_cal'] = i['sub_executor__predict_work'] * (1 - i['sub_executor__evaluate_factor']) / i['sub_exe_count']
i['sub_real_cal'] = i['sub_executor__real_work'] * (1 - i['sub_executor__evaluate_factor']) / i['sub_exe_count']
i['sub_count'] = 1 # 用于帮助累加程序计算每个用户的协办任务数量, sub_exe_count会返回此协办任务的协办人数在累加时导致计算错误
# print(i)
# print(str(i['sub_executor']))
# 用于按用户名合并任务会对指定字段进行累加类似GROUP BY(SUM),但会丢失无需计算的部分,因此之前需要单独构建姓名字典
def solve(dataset, group_by_key, sum_value_keys):
dic = defaultdict(Counter)
for item in dataset:
key = item[group_by_key]
vals = {k: item[k] for k in sum_value_keys}
dic[key].update(vals)
return dic
main_credit = solve(main_credit, 'username', ['main_pre_cal', 'main_real_cal', 'main_count'])
main_credit = dict(main_credit)
sub_credit = solve(sub_credit, 'username', ['sub_pre_cal', 'sub_real_cal', 'sub_count'])
sub_credit = dict(sub_credit)
total_credit = deepcopy(main_credit)
# 按用户名合并承办与协办任务字典
for key in sub_credit.keys():
if key in total_credit:
total_credit[key].update(sub_credit[key])
else:
total_credit[key] = sub_credit[key]
# print(total_credit['admin']['sub_pre_cal'])
# 根据字典内容,计算总工作量
for key, value in total_credit.items():
# print(value)
value['pre_cal'] = value['sub_pre_cal'] + value['main_pre_cal']
value['real_cal'] = value['sub_real_cal'] + value['main_real_cal']
value['real_name'] = user_name[key]
# total_credit = dict(main_credit.items() + sub_credit.items())
# for value in sub_credit.values():
# dict(value)
# print(sub_credit)
#
# new_pair = {}
# for doc, tab in sub_credit.items():
# new_pair[doc] = {}
# for word, freq in tab.items():
# new_pair[doc][word] = freq
# print(new_pair)
# return HttpResponse(str(main_credit)+str(sub_credit))
# 若total_credit为空不进行以下操作避免err
if total_credit:
current_user = total_credit[request.user.username]
# 累加该部门各个用户的工作量,计算部门工作量
department_cal = {}
temp_pre = []
depart_pre, depart_real, depart_count = 0, 0, 0
for username, value in total_credit.items():
print(username)
print(value['pre_cal'])
depart_pre = depart_pre + value['pre_cal']
depart_real = depart_real + value['real_cal']
depart_count = depart_count + value['main_count']
temp_pre.append(value['pre_cal'])
department_cal['pre_cal'] = depart_pre
department_cal['real_cal'] = depart_real
department_cal['depart_count'] = depart_count
department_cal['pre_avg'] = department_cal['pre_cal'] / len(total_credit)
department_cal['real_avg'] = department_cal['real_cal'] / len(total_credit)
else:
department_cal, current_user = {}, {}
# 为页面提供日期信息
date = str(year) + '' + str(month) + ''
# points = []
# point = User.objects.all()
# for i in point:
# points.append(i)
# points = User.objects.annotate(a=F('main_executor__evaluate_factor'))
# points = User.objects.annotate(a=Coalesce(Sum(F('main_executor__predict_work') * F('main_executor__evaluate_factor')) + Sum(F('sub_executor__predict_work') * F('sub_executor__evaluate_factor')), 0))
# points = User.objects.annotate(a=Sum(F('main_executor__predict_work') * F('main_executor__evaluate_factor')), b=Sum(F('sub_executor__predict_work') * F('sub_executor__evaluate_factor')))
# points = User.objects.annotate(a=Sum(F('main_executor__main_workload')))
main_credit = User.objects.filter(department=request.user.department, ).annotate(
pre_credit=Sum(
F('main_executor__predict_work') * F('main_executor__evaluate_factor'),
filter=Q(main_executor__deadline__year=year, main_executor__deadline__month=month),
distinct=True,
output_field=FloatField()
),
real_credit=Sum(
F('main_executor__real_work') * F('main_executor__evaluate_factor'),
filter=Q(main_executor__deadline__year=year, main_executor__deadline__month=month),
distinct=True,
output_field=FloatField()
)
).values('id', 'real_name', 'pre_credit', 'real_credit')
main_credit = [entry for entry in main_credit] # converts ValuesQuerySet into Python list
sub_credit = User.objects.filter(department=request.user.department).annotate(
pre_credit=Sum(
(F('sub_executor__predict_work') * (1 - F('sub_executor__evaluate_factor')) / F(
'sub_executor__sub_executor_count')
),
filter=Q(sub_executor__deadline__year=year, sub_executor__deadline__month=month),
output_field=FloatField()
),
real_credit=Sum(
(F('sub_executor__real_work') * (1 - F('sub_executor__evaluate_factor')) / F(
'sub_executor__sub_executor_count')
),
filter=Q(sub_executor__deadline__year=year, sub_executor__deadline__month=month),
output_field=FloatField()
)
).values('id', 'real_name', 'pre_credit', 'real_credit')
sub_credit = [entry for entry in sub_credit]
total_credit = main_credit + sub_credit
print(total_credit)
basic_user_credit = {}
if total_credit:
df = pd.DataFrame(total_credit)
cols = ['id', 'real_name', 'pre_credit', 'real_credit']
df = df.loc[:, cols]
result = df.groupby(['id', ]).sum()
cal_credit = result.T.to_dict('dict')
# print(cal_credit)
temp_credit = {}
basic_user_credit = {}
for key, values in cal_credit.items():
# print(values['real_credit'])
temp_credit['pre_credit'] = values['pre_credit']
temp_credit['real_credit'] = values['real_credit']
# print(temp_credit)
basic_user_credit.update({key: temp_credit})
# print(basic_user_credit)
temp_credit = {}
print(basic_user_credit)
else:
print("当前页Index无任何人员具有工作包")
for key in basic_user_cal:
basic_user_cal[key].update(basic_user_credit[key])
print(basic_user_cal)
# ids = []
# person_list = []
# for person in total_points:
# id = person["id"]
# temp = {}
# if id not in ids:
# ids.append(id)
# temp_list = filter(lambda x: x["id"] == person["id"], total_points)
# for i in temp_list:
# temp.update(i)
# person_list.append(temp)
# else:
# continue
# for i in main_points:
# for key, value in i.items():
# def sum_dict(a, b):
# temp = dict()
# # python3,dict_keys类似set | 并集
# for key in a.keys() | b.keys():
# temp[key] = sum([d.get(key, 0) for d in (a, b)])
# return temp
#
# def test():
# # [a,b,c]列表中的参数可以2个也可以多个自己尝试。
# return print(reduce(sum_dict, [a, b, c]))
context = {'users_data': basic_user_cal, 'date': date, 'current_user': current_user, 'department': whole}
# return HttpResponse(str(total_credit) + '\n' + str(department_cal))
context = {'date': date, 'users_data': total_credit, 'department_cal': department_cal,
'current_user': current_user}
return render(request, 'tasks/index.html', context)

View File

@ -36,7 +36,7 @@
<div class="info-box-content">
<span class="info-box-text">部门总任务数</span>
<span class="info-box-number">
{{ department.count|floatformat:'0'|default_if_none:'0' }}
{{ department_cal.depart_count|floatformat:'0'|default_if_none:'0' }}
<small></small>
</span>
</div>
@ -50,7 +50,7 @@
<div class="info-box-content">
<span class="info-box-text">部门预计总工作量</span>
<span class="info-box-number">
{{ department.pre_total|default_if_none:'0'|floatformat:'1' }}
{{ department_cal.pre_cal|default_if_none:'0'|floatformat:'1' }}
<small></small>
</span>
</div>
@ -64,7 +64,7 @@
<div class="info-box-content">
<span class="info-box-text">部门实际总工作量</span>
<span class="info-box-number">
{{ department.real_total|default_if_none:'0'|floatformat:'1' }}
{{ department_cal.real_cal|default_if_none:'0'|floatformat:'1' }}
<small></small>
</span>
</div>
@ -79,7 +79,7 @@
<div class="info-box-content">
<span class="info-box-text">部门预计平均工作量</span>
<span class="info-box-number">
{{ department.pre_avg|default_if_none:'0'|floatformat:'1' }}
{{ department_cal.pre_avg|default_if_none:'0'|floatformat:'1' }}
<small></small>
</span>
</div>
@ -93,7 +93,7 @@
<div class="info-box-content">
<span class="info-box-text">部门实际平均工作量</span>
<span class="info-box-number">
{{ department.real_avg|default_if_none:'0'|floatformat:'1' }}
{{ department_cal.real_avg|default_if_none:'0'|floatformat:'1' }}
<small></small>
</span>
</div>
@ -157,7 +157,7 @@
<div class="info-box-content">
<span class="info-box-text">承办任务数</span>
<span class="info-box-number">
{% for user in current_user %}{{ user.main_executor_count }}{% endfor %}
{{ current_user.main_count }}
<small></small>
</span>
</div>
@ -173,7 +173,7 @@
<div class="info-box-content">
<span class="info-box-text">协办任务数</span>
<span class="info-box-number">
{% for user in current_user %}{{ user.sub_executor_count }}{% endfor %}
{{ current_user.sub_count }}
<small></small>
</span>
</div>
@ -187,7 +187,7 @@
<div class="info-box-content">
<span class="info-box-text">预计工作量</span>
<span class="info-box-number">
{% for user in current_user %}{{ user.pre_credit|default_if_none:'0' }}{% endfor %}
{{ current_user.pre_cal|floatformat:'1'|default_if_none:'0' }}
<small></small>
</span>
</div>
@ -201,7 +201,7 @@
<div class="info-box-content">
<span class="info-box-text">实际工作量</span>
<span class="info-box-number">
{% for user in current_user %}{{ user.real_credit|default_if_none:'0' }}{% endfor %}
{{ current_user.real_cal|floatformat:'1'|default_if_none:'0' }}
<small></small>
</span>
</div>
@ -376,7 +376,7 @@
pointStrokeColor : '#c1c7d1',
pointHighlightFill : '#fff',
pointHighlightStroke: 'rgba(220,220,220,1)',
data : [{% for user in users_data.values %}'{{ user.sub_executor_count }}', {% endfor %}]
data : [{% for user in users_data.values %}'{{ user.sub_count }}', {% endfor %}]
},
{
label : '承办任务',
@ -387,7 +387,7 @@
pointStrokeColor : 'rgba(60,141,188,1)',
pointHighlightFill : '#fff',
pointHighlightStroke: 'rgba(60,141,188,1)',
data : [{% for user in users_data.values %}'{{ user.main_executor_count }}', {% endfor %}]
data : [{% for user in users_data.values %}'{{ user.main_count }}', {% endfor %}]
},
{
label : '预计工作量',
@ -398,7 +398,7 @@
pointStrokeColor : 'rgba(60,141,188,1)',
pointHighlightFill : '#fff',
pointHighlightStroke: 'rgba(60,141,188,1)',
data : [{% for user in users_data.values %}'{{ user.pre_credit|floatformat:'1' }}', {% endfor %}]
data : [{% for user in users_data.values %}'{{ user.pre_cal|floatformat:'1' }}', {% endfor %}]
},
{
label : '工作量',
@ -409,7 +409,7 @@
pointStrokeColor : 'rgba(60,141,188,1)',
pointHighlightFill : '#fff',
pointHighlightStroke: 'rgba(60,141,188,1)',
data : [{% for user in users_data.values %}'{{ user.real_credit|floatformat:'1' }}', {% endfor %}]
data : [{% for user in users_data.values %}'{{ user.real_cal|floatformat:'1' }}', {% endfor %}]
},
]
}