使用聚合与后期计算字段

时间:2014-06-06 14:54:44

标签: django

我在模型中有一个字段,它将根据两个值计算。问题现在我的所有代码都是使用手动SUMAVG

完成的

我想要做的是设计模型的另一种方法,同时保持相同的逻辑。我想要这样做的主要原因,因为我需要利用djagno聚合和注释函数。另外,要在数据库端计算这些值,而不是在Python中。

class Employee(models.Model):
    name = models.CharField(....)
    ..
    salary = models.FloatField(....)

class Benefit(models.Model):
    employee = models.ForeignKey('Employee')

    # this field can be
    # Percentage (ex %2 from employee main salary)
    # Fixed Price (ex $150)
    # days
    calculation_type = thetopchoices(FIX,PER,DAYS)

    # this field should be the value 
    # of the percentage or the fixed amount
    custom = models.PositiveIntegerField(....)

所以基本上,我有检查计算类型的方法,并根据它获得了收益的数额。

def calculate(self):
    if self.calculation_type == 'PER':
        return self.employee.salary * self.custom
    elif self.calculation_type == 'FIX':
        return self.custom
    else
        return ( self.employee.salary / 30 ) * self.custom

@property
def amount(self):
    return self.calculate()

现在问题是如何计算每个员工的福利总额。最好的解决方案是使用Django聚合在数据库中进行计算。但是,使用这种设计永远不会有效,因为Django需要数量才能成为一个真实的领域。

到目前为止我的解决方案,但我认为它没有效率。

def get_total_amount_of_benefits(self):
    total = 0
    for b in employee.benefit_set.all():
        total += b.amount

    return total

1 个答案:

答案 0 :(得分:1)

我认为您应重新定义Benefit模型,添加amount字段,该字段将根据模型calculation_type中的customsave字段值自动计算:

class Benefit(models.Model):
    employee = models.ForeignKey('Employee')

    # this field can be
    # Percentage (ex %2 from employee main salary)
    # Fixed Price (ex $150)
    # days
    calculation_type = thetopchoices(FIX,PER,DAYS)

    # this field should be the value 
    # of the percentage or the fixed amount
    custom = models.PositiveIntegerField(....)
    amount = models.PositiveIntegerField(...., editable=False) # auto calculated field in save

    def __init__(self, *args, **kwargs):
        super(Benefit, self).__init__(*args, **kwargs)
        self.__original_calc_type = self.calculation_type
        self.__original_custom = self.custom

    def calculate(self):
        employee = self.employee
        if self.calculation_type == 'PER':
            amount = employee.salary * self.custom
        elif self.calculation_type == 'FIX':
            amount = self.custom
        else
            amount = ( employee.salary / 30 ) * self.custom
        return amount

    def save(self, *args, **kwargs):
        recalculate = kwargs.pop('recalculate', False)
        if self.__original_calc_type != self.calculation_type or self.__original_custom != self.custom or recalculate:
            self.amount = self.calculate()
        super(Benefit, self).save(*args, **kwargs)
        self.__original_calc_type = self.calculation_type
        self.__original_custom = self.custom

现在可以轻松获得所有福利金额:

from django.db.models import Sum

class Employee(models.Model):
    ...
    ...

    @property
    def benefits_amount(self):
        d = self.benefit_set.aggregate(total_amount=Sum('amount'))
        return d['total_amount'] if d['total_amount'] else 0

如果您希望稍后根据您拥有的任何条件更新优惠,则需要按照以下方式执行此操作:

for benefit in employee.benefit_set.all():
    benefit.save(recalculate=True)
相关问题