django - 发票表格 - 在保存前验证小计和净总额
django - invoice form - validate the sub totals and net total before save
在 inlineformset_factory 的帮助下,我有一个由两个模型组成的发票表格 - Invoice 和 InvoiceItem。
我有以下 jquery 片段,通过读取每件商品的价格、数量、税费来计算个人总计和净总计。
function calculateSubTotal(obj){
subTotal = 0
parentDiv = obj.closest('.formset')
rate=parseFloat($(parentDiv).find('.rate').val())
quantity=parseInt($(parentDiv).find('.quantity').val())
tax=$(parentDiv).find('.tax option:selected').html()//.
tax=tax.match(/\d+/);
if(tax)
tax=parseFloat(tax[0],10)
else
return
if(!isNaN(rate) && !isNaN(quantity) && $.isNumeric(tax)){
subTotal = rate*quantity*(100+tax)/100
$(parentDiv).find('.total').val(subTotal)
}
}
function calculateTotal() {
subTotal=0
$('.total').each(function(){
//console.log($(this).id)
console.log($(this).val())
val=parseFloat($(this).val())
subTotal+=val
});
if(!isNaN(subTotal))
$('#id_total').val(subTotal)
}
$(document).ready(function() {
$('.formset .form-control').on("blur",function(e){
calculateSubTotal(this);
calculateTotal();
});
});
现在,我"believe",我需要在保存之前在服务器端进行所有这些计算,以防止任何手动correction/error由用户在表单中。 (如果我错了请纠正我)
我该如何继续?
这是我的 form_valid() 的 CreateView。
def form_valid(self, form):
context = self.get_context_data()
item_formset = context['item_formset']
with transaction.atomic():
form.instance.invoice_type=self.kwargs['invoice_type']
self.object = form.save(commit=False)
#self.object.save()
if item_formset.is_valid():
forms = item_formset.save(commit=False)
for form in forms:
**#calculate sub-total and assign net-total to parentform.instance.total**
item_formset.instance = self.object
item_formset.save()
return super().form_valid(form)
最简洁的方法可能是为 Invoice
和 InvoiceItem
创建自定义模型方法,然后在您的表单 save()
或视图的 form_vaild()
.[=18 中调用它们=]
一个例子models.py
:
class Invoice(models.Model):
customer = models.ForeignKey()
date = models.DateField()
total = models.DecimalField()
def process_invoice(self):
items = InvoiceItem.objects.filter(invoice=self)
for item in items:
... process item ....
item.save()
self.total = InvoiceItem.objects.filter(invoice=self).values('line_total').aggregate(tot=Sum('line_total')['tot']
... add whatever other logic you need ...
self.save()
然后在您的 form_valid
中,您将通过 self.object.process_invoice()
调用该方法。
围绕模型的 save()、post-save 信号、表单的 clean() 等进行了大量反复试验,最终得到了一些有用的东西。
这是现在的样子。
首先使用InvoiceItemForm
的clean()
方法确保每一行的总和是正确的
def clean(自我):
cleaned_data=super(InvoiceItemForm, self).clean()
total=cleaned_data.get('total')
if total:
tax=cleaned_data.get('tax')
calculated_total=price*(100+tax.rate)*quantity/100
if calculated_total != total:
raise forms.ValidationError({'total':["Total is incorrect."]})
return cleaned_data
接下来,在 CreateViews 的 form_valid() 方法下,遍历表单集中的每个表单并对各个表单求和。将此与主窗体的总值进行比较。
与 transaction.atomic():
form.instance.invoice_type=self.kwargs['invoice_type']
self.object = form.save(提交=假)
if item_formset.is_valid() == False:
return self.render_to_response(self.get_context_data(form=form,item_formset=item_formset ))
subTotal=0
i=0
for f in item_formset.forms:
subTotal += float(f.data['item-'+str(i)+'-total'])
i=i+1
if subTotal!= float(form.data['total']):
form.add_error('total', "Total is incorrect.")
return self.render_to_response(self.get_context_data(form=form,item_formset=item_formset ))
(欢迎任何可能的corrections/simplifications)
谢谢。
在 inlineformset_factory 的帮助下,我有一个由两个模型组成的发票表格 - Invoice 和 InvoiceItem。
我有以下 jquery 片段,通过读取每件商品的价格、数量、税费来计算个人总计和净总计。
function calculateSubTotal(obj){
subTotal = 0
parentDiv = obj.closest('.formset')
rate=parseFloat($(parentDiv).find('.rate').val())
quantity=parseInt($(parentDiv).find('.quantity').val())
tax=$(parentDiv).find('.tax option:selected').html()//.
tax=tax.match(/\d+/);
if(tax)
tax=parseFloat(tax[0],10)
else
return
if(!isNaN(rate) && !isNaN(quantity) && $.isNumeric(tax)){
subTotal = rate*quantity*(100+tax)/100
$(parentDiv).find('.total').val(subTotal)
}
}
function calculateTotal() {
subTotal=0
$('.total').each(function(){
//console.log($(this).id)
console.log($(this).val())
val=parseFloat($(this).val())
subTotal+=val
});
if(!isNaN(subTotal))
$('#id_total').val(subTotal)
}
$(document).ready(function() {
$('.formset .form-control').on("blur",function(e){
calculateSubTotal(this);
calculateTotal();
});
});
现在,我"believe",我需要在保存之前在服务器端进行所有这些计算,以防止任何手动correction/error由用户在表单中。 (如果我错了请纠正我)
我该如何继续?
这是我的 form_valid() 的 CreateView。
def form_valid(self, form):
context = self.get_context_data()
item_formset = context['item_formset']
with transaction.atomic():
form.instance.invoice_type=self.kwargs['invoice_type']
self.object = form.save(commit=False)
#self.object.save()
if item_formset.is_valid():
forms = item_formset.save(commit=False)
for form in forms:
**#calculate sub-total and assign net-total to parentform.instance.total**
item_formset.instance = self.object
item_formset.save()
return super().form_valid(form)
最简洁的方法可能是为 Invoice
和 InvoiceItem
创建自定义模型方法,然后在您的表单 save()
或视图的 form_vaild()
.[=18 中调用它们=]
一个例子models.py
:
class Invoice(models.Model):
customer = models.ForeignKey()
date = models.DateField()
total = models.DecimalField()
def process_invoice(self):
items = InvoiceItem.objects.filter(invoice=self)
for item in items:
... process item ....
item.save()
self.total = InvoiceItem.objects.filter(invoice=self).values('line_total').aggregate(tot=Sum('line_total')['tot']
... add whatever other logic you need ...
self.save()
然后在您的 form_valid
中,您将通过 self.object.process_invoice()
调用该方法。
围绕模型的 save()、post-save 信号、表单的 clean() 等进行了大量反复试验,最终得到了一些有用的东西。
这是现在的样子。
首先使用
InvoiceItemForm
的clean()
方法确保每一行的总和是正确的def clean(自我): cleaned_data=super(InvoiceItemForm, self).clean()
total=cleaned_data.get('total') if total: tax=cleaned_data.get('tax') calculated_total=price*(100+tax.rate)*quantity/100 if calculated_total != total: raise forms.ValidationError({'total':["Total is incorrect."]}) return cleaned_data
接下来,在 CreateViews 的 form_valid() 方法下,遍历表单集中的每个表单并对各个表单求和。将此与主窗体的总值进行比较。
与 transaction.atomic(): form.instance.invoice_type=self.kwargs['invoice_type'] self.object = form.save(提交=假)
if item_formset.is_valid() == False: return self.render_to_response(self.get_context_data(form=form,item_formset=item_formset )) subTotal=0 i=0 for f in item_formset.forms: subTotal += float(f.data['item-'+str(i)+'-total']) i=i+1 if subTotal!= float(form.data['total']): form.add_error('total', "Total is incorrect.") return self.render_to_response(self.get_context_data(form=form,item_formset=item_formset ))
(欢迎任何可能的corrections/simplifications)
谢谢。