【问题标题】:How to find the percentage of employee scores using django如何使用 django 查找员工得分的百分比
【发布时间】:2021-08-04 01:42:50
【问题描述】:

我有一个名为 Task 的表。它捕获任务、任务分数和分配给它的员工。 我想使用他一周的总任务分数(持续时间应该是动态的。最好是输入字段)和分配的总分数来计算员工的表现。 我正在考虑汇总实际分数,然后除以购买总分,然后乘以 100 得到百分比。我的主要挑战是在哪里执行此计算。我应该创建一个称为性能的模型并使用一个函数吗?或者谁能​​告诉我怎么做?

这是模型;

class Task(models.Model):
    title = model.CharField(max_length=200)
    scores = models.IntegerField(null=True, blank=True)

    def __str__(self):
        return self.name

这是我要使用的公式。 Performance(%) = 实际分数/总分*100。总分应为输入字段。

更新 以下是相关模型。我正在使用 User 模型作为 Employee。

**USER OR EMPLOYEE MODEL**
 
class User(AbstractUser):
    ROLE_CHOICES = (
    ("STAFF", "Staff"),
    ("HOD", "Hod"),
    ("CEO", "Ceo"),
    )

    GENDER_CHOICES = (
    ("Male", "Male"),
    ("Female", "Female")
    )

    CONFIRMATION_CHOICES = (
        ("YES", "yes"),
        ("NO", "no")
    )

    UNDERTAKING_CHOICES = (
        ("YES", "yes"),
        ("NOT YET", "Not yet")
    )

    GENDER_CHOICES = (
        ("Male", "Male"),
        ("Female", "Female")
    )

    EMPLOYEE_TYPE_CHOICES = (
        ("Permanent", "Permanent"),
        ("Contract", "Contract")
    )

    first_name = models.CharField(max_length=100, blank=True)
    last_name = models.CharField(max_length=100, blank=True)
    middle_name = models.CharField(max_length=100, null=True, blank=True)
    email = models.EmailField(null=True)
    avatar =  models.ImageField(upload_to='images/avatar', null=True, blank=True)
    department = models.ForeignKey(Department, related_name='userdept', on_delete=models.CASCADE, null=True)
    role = models.ForeignKey(Role, related_name='userrol', on_delete=models.CASCADE, null=True, blank=True)
    user_role = models.CharField(max_length=100, choices=ROLE_CHOICES, null=True)
    avatar = models.ImageField(upload_to="avatars", null=True, blank=True)
    is_hod = models.BooleanField(default=False)
    is_ceo = models.BooleanField(default=False)
    is_admin = models.BooleanField(default=False)
    is_superuser = models.BooleanField(default=False)
    gender = models.CharField(max_length=100, choices=GENDER_CHOICES, null=True, blank=True)
    cell_phone = models.CharField(max_length=20, blank=True, null=True)
    employee_id = models.CharField(max_length=200, null=True, blank=True)
    supervisor = models.CharField(max_length=200, null=True, blank=True)
    work_email = models.EmailField(null=True, blank=True)
    work_phone = models.CharField(max_length=20, blank=True)
    start_date = models.CharField(max_length=20, blank=True)
    salary = models.CharField(max_length=20, blank=True, null=True)
    work_location = models.CharField(max_length=20, null=True, blank=True)
    probation_length = models.CharField(max_length=20, null=True, blank=True)
    pay_slip_type = models.CharField(max_length=20, null=True, blank=True)
    can_terminate = models.CharField(max_length=20, null=True, blank=True)
    dob = models.CharField(max_length=20, null=True, blank=True)
    employee_type = models.CharField(max_length=20, choices=EMPLOYEE_TYPE_CHOICES, null=True, blank=True)
    comfirmed = models.CharField(max_length=3, choices=CONFIRMATION_CHOICES, null=True)
    undertaking = models.CharField(max_length=8, choices=UNDERTAKING_CHOICES, null=True)
    leave_days = models.IntegerField(null=True, blank=True) 
    line_manager = models.CharField(max_length=20, null=True, blank=True)   
    last_promotion_date = models.CharField(max_length=20, null=True, blank=True)
    
    
    def __str__(self):
        return self.first_name+' '+self.last_name


**TASK MODEL**

from django.db import models
from departments.models import Department
from akps.models import Akp
from users.models import User
from goals.models import OrganisationGoal, OrganisationSubGoal, DepartmentGoal
from django.template.loader import render_to_string
from django.core.mail import send_mail
from django.core.mail import EmailMultiAlternatives
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.utils.text import slugify
# from django.template.loader import render_to_string
from django.core.mail import send_mail
from django.core.mail import EmailMultiAlternatives
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.utils.text import slugify
from django.core.exceptions import ValidationError


class Task(models.Model):
    STATUS_CHOICES = (
    ("COMPLETED", "completed"),
    ("FAILED", "failed"),
    )
    department = models.ForeignKey(Department, related_name='soussdepartmentt', on_delete=models.CASCADE, null=True)
    akp = models.ForeignKey(Akp, related_name='sousakpp', on_delete=models.CASCADE, null=True)
    organisationgoal = models.ForeignKey(OrganisationGoal, on_delete=models.CASCADE, null=True)
    organisationsubgoal = models.ForeignKey(OrganisationSubGoal, on_delete=models.CASCADE, null=True, blank=True)
    departmentgoal = models.ForeignKey(DepartmentGoal, on_delete=models.CASCADE, related_name='departgoal', null=True, blank=True)
    name = models.CharField(max_length=300, null=True)
    description = models.TextField(max_length=1000, null=True)
    assignedby = models.ForeignKey(User, on_delete=models.CASCADE, related_name='taskassignb', null=True, blank=True)
    assignedto = models.ForeignKey(User, on_delete=models.CASCADE, related_name='taskassignt', null=True, blank=True)
    user = models.ForeignKey(User, related_name='usertas', on_delete=models.CASCADE, null=True)
    scores = models.IntegerField(null=True, blank=True)
    status = models.CharField(max_length=10, choices=STATUS_CHOICES, null=True, blank=True)
    email = models.EmailField(null=True)
    due_date = models.DateField(null=True)
    created_at = models.DateTimeField(auto_now_add=True, null=True)
    updated_at = models.DateTimeField(auto_now=True, null=True)


    def __str__(self):
        return self.name


    def clean(self):
        other_tasks = Task.objects.exclude(pk=self.pk) \
            .filter(departmentgoal=self.departmentgoal)

        if other_tasks.count() > 0:
            contributed = (
                other_tasks.values("departmentgoal")
                .annotate(total=models.Sum("scores"))
                .values_list("total", flat=True)[0]
            )
        else:
            contributed = 0

        if self.scores and self.scores + contributed > self.departmentgoal.scores:
            raise ValidationError({"scores": "Score is too much"})

这是一个场景;

  • 用户 A 已完成每周 10 项任务中的 8 项。他一共得到18分。注意:每周分数不能超过 20 分。

  • 上述过程每周重复一次。比方说第二周,他得了 20 分。

  • 1 个月、4 个月、6 个月或 1 年后,我想 计算他的表现并显示在他的仪表板上。数学是实际分数/总分* 100。我相信这可以通过用户和任务模型来实现,但我不知道如何实现。

用户和仪表板视图

from tasks.models import Task
from users.models import User
from goals.models import DepartmentGoal, OrganisationGoal
from django.utils import timezone
from datetime import timedelta

def dashboard(request):
    
    completed_tasks = Task.objects.filter(status="COMPLETED", assignedto=request.user).count()
    failed_tasks = Task.objects.filter(status="FAILED", assignedto=request.user).count()

    debt_complt_goal = DepartmentGoal.objects.filter(status="COMPLETED", department=request.user.department).count()
    debt_failed_goal = DepartmentGoal.objects.filter(status="FAILED", department=request.user.department).count()

    complt_org_goals = OrganisationGoal.objects.filter(status="COMPLETED").count()
    failed_org_goals = OrganisationGoal.objects.filter(status="FAILED").count()

    return render (request, 'home.html', {
        'completed_tasks':completed_tasks, 
        'failed_tasks':failed_tasks, 
        'debt_complt_goal':debt_complt_goal,
        'debt_failed_goal':debt_failed_goal,
        'complt_org_goals':complt_org_goals,
        'failed_org_goals':failed_org_goals,
    })



from django.shortcuts import render, redirect, get_object_or_404, HttpResponse
from .models import Profile, User
from .forms import ProfileForm, CreateUserForm, UserSetPasswordForm
from django.contrib.auth.forms import AuthenticationForm
from django.contrib.auth import authenticate, login, logout
from django.contrib import messages


def list_users_view(request):
    department = request.user.department
    dept_users = User.objects.filter(department=department)
    users = User.objects.all()
    context = {
        'users':users,
        'dept_users':dept_users
        }
    return render(request, 'users/list-users.html', context)

【问题讨论】:

  • 这里的总分是多少?所有分数的总和还是一个固定值?
  • 如果每周任务得分为 20 分,但员工得分为 10 分。如果你要在 Django 中实现它,他的分数会是多少?
  • 我需要更多信息来更好地了解您的问题。您的 Employee 模型是什么样的?Task 模型中的哪个字段与Employee 的实例相关联?当模型上没有日期/日期时间字段时,如何计算每周聚合?
  • @Scratch'N'Purr 我编辑了这个问题。我相信这回答了你的问题。
  • @ThaddeausIorbee 好的,我现在得到了更清晰的图像。 Task 模型中的 assignedtouser 字段有什么区别?您使用这两个字段中的哪一个将任务与用户相关联(我猜是assignedto)?

标签: python python-3.x django django-annotate django-aggregation


【解决方案1】:

这是我解释的标准:

  1. 使用assignedto 字段将任务与用户相关联。
  2. 任务有一个截止日期,在计算性能时将根据时间范围参数使用该截止日期。
  3. 任务要么完成要么失败。
  4. 如果用户完成任务,用户将获得与该任务相关的分数。

解决方案

在您的 User 模型上添加自定义方法来计算性能。该方法将要求 startend 日期参数来计算时间范围之间的性能。

from django.db.models import Sum, Q


class User(AbstractUser):
    ...

    def performance(self, start, end):
        actual = Sum("scores", filter=Q(status="completed"))

        q = self.taskassignt.filter(
            due_date__gte=start,
            due_date__lt=end  # `end` is excluded from the range
        ).annotate(actual=actual, total=Sum("scores"))

        return (q[0].actual / q[0].total) * 100

请注意,时间范围实现将 end 从范围中排除,因为它使用 lt(小于)运算符。

方法的用法是:

from django.utils import timezone
from datetime import timedelta


# user is a `User` instance
user.performance(timezone.now() + timedelta(days=-7), timezone.now())

【讨论】:

  • 感谢您的及时回复。我会实施并回来。
  • 我有点困惑。我不知道如何在我现有的视图中调用user.performance(timezone.now() + timedelta(days=-7), timezone.now())。我用相关观点更新了我的问题。仪表板视图和用户视图。请告诉我如何调用这个类方法。我希望每个用户都能在他们的仪表板上查看他们的表现。
  • @ThaddeausIorbee 因为您的用户是request.user,所以您使用request.user.performance(timezone.now() + timedelta(days=-7), timezone.now()) 调用该方法。请注意,传递给该方法的参数是一周的时间范围。您可以将所需的任何日期参数传递给方法,只要它们是日期类型。
  • 我将此答案标记为正确,因为它非常接近解决我的问题。感谢@Scratch'N'Purr 和所有做出贡献的人。
  • 你能弄清楚这个错误是从哪里来的吗? performance = get_performance(timezone.now() + timedelta(days=-7), timezone.now()) TypeError: get_performance() missing 1 required positional argument: 'end'
【解决方案2】:

我无法将其完全映射到您上面的模型,因为您缺少一些东西,例如用户映射和时间戳,但它应该是这样的:

from django.db.models import Count, Sum, F
from datetime import datetime, timedelta

end_date = datetime.now()
start_date = end_date - timedelta(days=7)
performance = Sum(F('scores')) / (Count(F('scores')) * 100)
Task.objects.filter(
    employee_id=123, 
    timestamp__gt=start_date, 
    timestamp__lte=end_date
).aggregate(
    performance=performance
)

【讨论】:

  • 嗨@shapiromatron,感谢您的及时回复。这一切都将成为任务模型中的一个功能吗?我是 django 的初学者。
  • 是的,它可能是任务模型上的一个类方法,或者您可以花哨的方法对查询集进行子类化。如果只是几个,那么我会在任务模型上创建一个新的类方法。
  • 好的。当我在家时,我会实施它。我会通知你结果。这意味着我将在任务模型上创建一个性能字段,对吗?因为性能 = 性能。
  • 不,这是一个查询,不是您要存储在数据库中的东西,至少在当前模型中是这样。您可以使用此汇总结果创建一个新的数据库表。
  • 好的。谢谢。会回来的。
猜你喜欢
  • 1970-01-01
  • 2021-11-12
  • 2017-11-12
  • 1970-01-01
  • 2019-06-08
  • 1970-01-01
  • 2020-11-22
  • 2020-04-15
  • 1970-01-01
相关资源
最近更新 更多