【问题标题】:Django - how to perform arithmetic operations in a class in models.pyDjango - 如何在 models.py 中的类中执行算术运算
【发布时间】:2018-04-18 17:17:10
【问题描述】:

我想通过我的公式计算员工的工资

total_salary = (time_out - time_in )*base_salary + (time_out - 8PM)*base_salary*0.20

这是我的模型:

class salary(models.Model):
    empname = models.ForeignKey('employee1',default='0',on_delete=models.CASCADE)
    base_salary = models.IntegerField(default='0', help_text="Base Salary")
    time_in = models.DateTimeField(default=datetime.now, blank=True)
    time_out = models.DateTimeField(default=datetime.now, blank=True)
    total_salary = models.CharField(max_length=20,default='0',blank=True,editable=False)

    def default_over_time():
        now = datetime.now()
        start = now.replace(hour=8, minute=0, second=0, microsecond=0)
        return start if start > now else start + timedelta(days=1)

    def save(self,*args,**kwargs):
        self.total_salary=(self.time_out - self.time_in)
        self.total_salary=(self.time_out - self.time_in )*  self.base_salary + (self.time_out - self.default_over_time) * self.base_salary*0.20
        self.total_salary=str(self.total_salary)
        super(salary,self).save(*args,**kwargs)

【问题讨论】:

  • 类是什么意思?你想在视图中看到它吗?或者你想要它在模型本身?还请妥善安排您的代码。如果您正在寻找自定义模型字段,那么stackoverflow.com/questions/28529179/…
  • @py-D 我已经安排好了我的代码。我想用我的公式计算薪水 --> total_salary=(time_out - time_in )* base_salary + (time_out - 8PM) * base_salary*0.20
  • 类是什么意思?你想在视图中看到它吗?或者你想在模型本身中使用它?
  • @py-D 模型本身
  • okz,这意味着您必须覆盖 django 模型保存方法。所以参考这个stackoverflow.com/questions/4269605/…

标签: django django-models


【解决方案1】:

在回答之前,我想对您的代码做一些观察:

  1. 不要将default='0' 参数与ForeignKey 一起使用。
  2. base_salaryIntegerField,因此不应使用字符串作为默认值。
  3. 您的base_salary 是每小时吗?还是每天?还是一个月?
  4. 我建议使用Djangos timezone 而不是pythons datetime 库。
  5. 您确定要为您的total_salary 提供CharField 吗?

以下是我关于如何计算工资的建议:

from datetime import timedelta
from django.db import models
from django.utils import timezone as tz

class Salary(models.Model):
    employee = models.ForeignKey('Employee', on_delete=models.CASCADE)
    base_salary = models.IntegerField(default=0)
    time_in = models.DateTimeField(default=tz.now, null=True, blank=True)
    time_out = models.DateTimeField(default=tz.now, null=True, blank=True)
    total_salary = models.CharField(max_length=20, default='0')

    def calculate_salary(self):
        worked_hours = (self.time_out - self.time_in).total_seconds() / 60 / 60
        overtime_hours = 0

        # make sure you use timezone aware objects
        # https://docs.djangoproject.com/en/2.0/topics/i18n/timezones/#naive-and-aware-datetime-objects
        same_day_8pm = self.time_out.replace(hour=20, minute=0, second=0, microsecond=0)
        if self.time_out > same_day_8pm:
            overtime_hours = (self.time_out - same_day_8pm).total_seconds() / 60 / 60

        salary_1 = worked_hours * self.base_salary
        salary_2 = overtime_hours * self.base_salary * 0.2
        total_salary = salary_1 + salary_2

        # careful: this will be a 'float', not an 'int'
        # with round() using 0 decimal digits you get an 'int'
        # total_salary = round(total_salary, 0)

        return total_salary

    def save(self,*args,**kwargs):
        # are you really sure that you want to save a string ???
        self.total_salary = str(self.calculate_salary())
        super().save(*args, **kwargs)

@Ashish 发表以下评论后编辑:

我的要求已更改,我必须将 DateTimeField 更改为 timein 和 timeout 的 TimeField ......但是当我在您给定的答案中进行更改时,我面临一个错误(异常值:不支持的操作数类型( s) for -: 'datetime.time' 和 'datetime.time' )

我建议不要在这种情况下使用TimeField,因为它会使计算更加复杂。 使用DateTimeField 存储额外的日期信息也没有什么坏处(例如,当time_intime_out 在不同的日期时,可能就在午夜之后)。

但是,如果您在这件事上束手无策,那么让您解决:

您看到错误是因为djangos TimeField 使用了不支持- 操作的pythons datetime.time。 有关类似任务,另请参阅 this post

您可以通过像这样转换为datetime.datetime 对象来克服这个问题:

import datetime as dt
new_time_in = dt.datetime(
    year=2000, month=1, day=1,  # choose an arbitrary date
    hour=time_in.hour,
    minute=time_in.minute,
    second=time_in.second,
    tzinfo=time_in.tzinfo)
new_time_out = dt.datetime(
    year=2000, month=1, day=1,  # use the same date as before
    hour=time_out.hour,
    minute=time_out.minute,
    second=time_out.second,
    tzinfo=time_out.tzinfo)

【讨论】:

  • 非常感谢@Ralf 这是我多年来一直在寻找的完美解决方案非常感谢
  • 你能帮我解决这个问题吗..stackoverflow.com/questions/49909926/…
  • 先生需要更多帮助
  • 我的要求已更改,我必须将 DateTimeField 更改为 timein 和 timeout 的 TimeField ......但是当我在您给定的答案中进行更改时,我面临一个错误(异常值: 不支持的操作数类型 -: 'datetime.time' 和 'datetime.time' )
  • 我在回答的末尾添加了一些想法。
【解决方案2】:

我不知道您将如何根据基本工资计算工资,但就您的公式而言,self.time_out - self.time_in 它会给您一个日期时间对象。

因此您必须将其转换为秒或小时。喜欢

a1 = self.time_out - self.time_in
total_sec = a1.total_seconds() 

self.time_out - self.default_over_time 也一样

编辑:

根据您的评论,您必须将时差转换为小时,然后您必须在公式中使用相同的值,您可以使用 divmod。 前任。

a1 = self.time_out - self.time_in
total_sec = a1.total_seconds()
minutes,second = divmod(total_sec,60)
hours,minutes = divmod(minutes,60)

从上面您将获得总小时数,并且可以在您的公式中使用相同的小时数。

编辑 2:

将时间转换为日期时间,然后求差。前任。

datetime.strptime(self.time_out.strftime('%H:%I'),'%H:%I') - datetime.strptime(self.time_in.strftime('%H:%I'),'%H:%I') 

【讨论】:

  • 谢谢,但我需要您帮助 Ralf 在我的问题下方提供的答案……我的要求已更改,我必须将 DateTimeField 更改为 timein 和 timeout 的 TimeField ... .....但是当我在您给定的答案中进行更改时,我面临一个错误(异常值:不支持的操作数类型 -: 'datetime.time' 和 'datetime.time' )
  • 将时间转换为日期时间,然后求不同。前任。 datetime.strptime(self.time_out.strftime('%H:%I'),'%H:%I') - datetime.strptime(self.time_in.strftime('%H:%I'),'%H :%I') @Ashish
猜你喜欢
  • 2013-04-16
  • 2017-04-15
  • 2014-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-17
  • 2021-05-03
  • 2022-07-07
相关资源
最近更新 更多