什么是最佳实践"用于Django 1.10 +中的发票计算?

时间:2017-04-25 14:12:52

标签: python django erp invoice

如果有两个型号:

class Invoice(models.Model):
    class Meta:
        ordering = ('-date_added', )

    number = models.CharField(max_length=10,)
    comments = models.TextField(blank=True, help_text="Notes about this invoice." )
    total = models.DecimalField(max_digits=9, decimal_places=2, default="0" )
    date_added = models.DateTimeField(_('date added'), auto_now_add=True)
    date_modified = models.DateTimeField(_('date modified'), auto_now=True)

def __unicode__(self):
    return "%s: total %s" % (self.number, self.total)

class Part(models.Model):
    for_invoice = models.ForeignKey(Invoice)
    description = models.CharField(max_length=200, blank=True, help_text=_("Briefly describe the part.") )
    supplier = models.CharField(max_length=100, blank=True, help_text=_("Supplier Name.") )
    supplier_number = models.CharField(max_length=100, blank=False, help_text=_("Supplier's order number.") )
    qty = models.DecimalField(max_digits=3, decimal_places=0, blank=False, null=False, help_text=_("How many are needed?") )
    cost = models.DecimalField(max_digits=7, decimal_places=2, blank=True, null=True, help_text=_("Price paid per unit") )
    line_total = models.DecimalField(max_digits=9, decimal_places=2, default="0")
    date_added = models.DateTimeField(auto_now_add=True)
    date_modified = models.DateTimeField(auto_now=True)

def __unicode__(self):
    return "%s: total %s" % (self.for_invoice, self.line_total)

我看到的第一个选择是可以实现" line_total"或"总计"作为计算模型字段。但是,如果你这样做,那么你就不能按照" line_total"对变更列表进行排序。或"总计",用户希望能够做到这一点。所以我在模型上创建了一个保存的字段。

阅读Django 1.10文档我看到4个地方可以定义代码来计算和更新"总计"和" line_total"字段:

  1. ModelAdmin.save_model(request,obj,form,change)和ModelAdmin.save_formset(request,form,formset,change)
  2. ModelAdmin.save_related(请求,表单,表单集,更改)
  3. model.save(self,* args,** kwargs))
  4. 保存信号
  5. 在我看来,保存信号太低 - 与单个模型保存事件相关联,它永远不会访问请求或会话。所以它会令人烦恼"尝试整理所有" Part"记录?

    同样,似乎model.save方法也过于细化。这将是"方便"如果我可以使用Invoice.save方法,因为它可以通过Invoice.part_set.all()轻松访问所有相关部分,循环该查询集将是更新line_total,然后是主要总数的简单方法。但是,此时是否会保存所有新的/更改的部分记录?它无法访问HttpRequest。

    我认为同样适用于Admin的save_model。但是,我有一个模糊的记忆,可以确保首先保存相关的部分。我在管理员

    中的发票添加/编辑页面上使用内联列出了部件

    我刚刚在ModelAdmin.save_related中添加了!我忘记了那一个。由于此时会保存主发票,也许这是更新所有部分记录,然后更新父总数的最佳位置?

    提前致谢!

1 个答案:

答案 0 :(得分:0)

感谢 Alasdair 的建议,但是,此客户端不需要完整的自定义解决方案。所以我坚持使用Admin调整。

我正在使用选项2进行测试:管理员的 save_related 功能。代码如下:

from decimal import Decimal

  def save_related(self, request, form, formsets, change):
    total = Decimal('0.00')
    for myform in formsets:
      for mf in myform.forms:
        # Skip empty rows (if any):
        if len(mf.cleaned_data) > 0:
          # Update item line total from item quantity and price:
          mf.instance.line_total = mf.instance.qty * mf.instance.cost
          # Add line item total to grand total:
          total += mf.instance.line_total
          # re-save line item:
          mf.instance.save()
    # Update grand total on the invoice:
    form.instance.total = total
    # re-save the invoice record:
    form.instance.save()
    # Chain to inherited code:
    super(InvoiceAdmin, self).save_related(request, form, formsets, change)

抱歉可变名称不佳。内线形式是2级深度让我措手不及。我猜第一层是一组formsets(只有一个),第一个formset里面是我的表单。一切都有 .instance 对象,我认为这些对象已经保存了。一个惊喜,因为我以为我读到这个函数的默认动作是保存表单集(主表单已经保存)。

无论如何,它都有效,所以我假设我误解了文档。