2017-04-25 38 views
0

如果一个人有两种型号:什么是Django 1.10+发票计算的“最佳实践”?

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”或“total”对改变列表进行排序,并且用户希望能够做到这一点。所以我让它们在模型上保存起来。

读取的Django 1.10文档我看到4个地方代码可被限定成计算和更新“总”和“line_total”字段:

  1. ModelAdmin.save_model(请求,OBJ,形式,变更)和ModelAdmin.save_formset(请求,形式,表单集,变更)
  2. ModelAdmin.save_related(请求,形式,表单集,变更)
  3. model.save(个体,*指定参数时,** kwargs))
  4. 保存信号

在我看来,保存信号太低级 - 绑定到单个模型保存事件,并且永远无法访问请求或会话。因此,尝试整理所有“Part”记录会很“烦人”?

同样,看起来model.save方法也会过于细化。如果我可以使用Invoice.save方法,那将是“方便的”,因为它可以通过Invoice.part_set.all()方便地访问所有关联的部分,循环该查询集将是更新line_total的简单方法,然后主总。但是,现在所有新的/更改的零件记录都会保存吗?它将无法访问HttpRequest。

我认为同样适用于Admin的save_model。但是,我有一个模糊的记忆,它可能会确保相关的零件首先被保存。我在Admin中的Invoice添加/编辑页面上使用内联列出部件。

我刚加入ModelAdmin.save_related!我忘了那个。由于此时主发票将被保存,可能这是更新所有零件记录的最佳位置,然后更新父项总数?

在此先感谢!

+2

你*可以*按照计算的字段进行排序。看[这个答案](http://stackoverflow.com/a/42660093/113962)。 – Alasdair

回答

0

感谢阿拉斯代尔的建议,但是,这个客户端不想要一个完整的自定义解决方案。所以我坚持管理调整。

我正在测试使用选项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级的内联表格吓倒了。我猜第一层是一组formset(只有一个),第一个formset里面是我的表单。一切都有。实例对象,我认为这表明他们已经被保存。一个惊喜,因为我认为我读了这个函数的默认动作是保存表单集(主表单已经保存)。

无论如何,它的作品,所以我会假设我误解了文档。