Django 使用来自其他表单的数据验证表单集

Django 使用来自其他表单的数据验证表单集,django,django-forms,Django,Django Forms,我必须对表单和表单集进行一些验证。表格中的金额必须等于表格中的金额之和 经过大量的谷歌搜索,我找到了一个解决方案,我在baseformset中添加了一个自定义的init,如下所示: class BaseSplitPaymentLineItemFormSet(BaseFormSet): def __init__(self, cr=None, *args, **kwargs): self._cr = cr super().__init__(*args, **k

我必须对表单和表单集进行一些验证。表格中的金额必须等于表格中的金额之和

经过大量的谷歌搜索,我找到了一个解决方案,我在baseformset中添加了一个自定义的init,如下所示:

class BaseSplitPaymentLineItemFormSet(BaseFormSet):
    def __init__(self, cr=None, *args, **kwargs):
        self._cr = cr
        super().__init__(*args, **kwargs)
    def clean(self):
        if any(self.errors):
            return
        sum_dr = 0
        for form in self.forms:
            sum_dr += form.cleaned_data.get('dr')
        if sum_dr != float(self._cr):
            raise forms.ValidationError('The amount entered needs to equal the sum of the split payments.')
然后,在实例化表单集时,我从表单传递amount值,以便在表单集验证中使用该值:

lineitem_formset = LineItemFormSet(form.data['amount'], request.POST)
这对于使用formset\u factory()的create\u new视图非常有效。今天早上,我使用inline_formsetfactory()编写了更新视图,但现在出现了一个错误:

\uuuu init\uuuuuuu()得到一个意外的关键字参数“instance”

我只对自定义init的工作原理有一个基本的了解,所以我找不到解决这个错误的方法

Forms.py:

class SplitPaymentForm(forms.Form):
    date = forms.DateField(widget=DateTypeInput())
    account = GroupedModelChoiceField(queryset=Ledger.objects.filter(coa_sub_group__type='a').order_by('coa_sub_group__name','name'), choices_groupby = 'coa_sub_group')
    store = forms.CharField(required=True)
    amount = forms.DecimalField(decimal_places=2)

class SplitPaymentLineItemForm(ModelForm):
    ledger = GroupedModelChoiceField(queryset=Ledger.objects.all().order_by('coa_sub_group__name', 'name'), choices_groupby = 'coa_sub_group', empty_label="Ledger", required=True)
    project = forms.ModelChoiceField(queryset=Project.objects.filter(status=0), empty_label="Project", required=False)
    class Meta:
        model = LineItem
        fields = ['description','project', 'ledger','dr',]
    # This init disallows empty formsets
    def __init__(self, *arg, **kwarg):
            super(SplitPaymentLineItemForm, self).__init__(*arg, **kwarg)
            self.empty_permitted = False


class BaseSplitPaymentLineItemFormSet(BaseFormSet):
    def __init__(self, cr=None, *args, **kwargs):
        self._cr = cr
        super().__init__(*args, **kwargs)
    def clean(self):
        if any(self.errors):
            return
        sum_dr = 0
        for form in self.forms:
            sum_dr += form.cleaned_data.get('dr')
        if sum_dr != float(self._cr):
            raise forms.ValidationError('The amount entered needs to equal the sum of the split payments.')
Views.py:

def split_payments_new(request):
    LineItemFormSet = formset_factory(SplitPaymentLineItemForm, formset=BaseSplitPaymentLineItemFormSet, extra=2)
    if request.method == 'POST':
        form = SplitPaymentForm(request.POST)
        lineitem_formset = LineItemFormSet(form.data['amount'], request.POST)
        if form.is_valid() and lineitem_formset.is_valid():
            q0 = JournalEntry(user=request.user, date=form.cleaned_data['date'], type="SP",)
            q1 = LineItem(journal_entry=q0, description=form.cleaned_data['store'], ledger=form.cleaned_data['account'], cr=form.cleaned_data['amount'])
            q0.save()
            q1.save()
            for lineitem in lineitem_formset:
                q2 = LineItem(journal_entry=q0,description=lineitem.cleaned_data.get('description'),ledger=lineitem.cleaned_data.get('ledger'),project=lineitem.cleaned_data.get('project'),dr=lineitem.cleaned_data.get('dr'))
                q2.save()
            messages.success(request, "Split payment successfully created.")
            return HttpResponseRedirect(reverse('journal:split_payments_show_detail', kwargs={'pk': q0.id}) )
    else:
        form = SplitPaymentForm(initial = {'date': datetime.date.today().strftime('%Y-%m-%d')})
        lineitem_formset = LineItemFormSet()
    return render(request, 'journal/split_payments_new.html', {'form': form, 'formset': lineitem_formset})

def split_payments_update(request, pk):
    journal_entry = get_object_or_404(JournalEntry, pk=pk, type="SP")
    lineitem = LineItem.objects.get(journal_entry=journal_entry.id, dr__isnull=True)

    initial = {
        'date': journal_entry.date.strftime('%Y-%m-%d'),
        'account': lineitem.ledger,
        'store': lineitem.description,
        'amount': lineitem.cr,
    }
    form = SplitPaymentForm(initial=initial)

    LineItemFormSet = inlineformset_factory(JournalEntry, LineItem, form=SplitPaymentLineItemForm, formset=BaseSplitPaymentLineItemFormSet, extra=0)
    lineitem_formset = LineItemFormSet(instance=journal_entry)

    if request.method == 'POST':
        lineitem_formset = LineItemFormSet(form.data['amount'], request.POST, instance=journal_entry)
        form = SplitPaymentForm(request.POST)
        if lineitem_formset.is_valid() and form.is_valid():
            lineitem_formset.save()
            journal_entry.date = form.cleaned_data['date']
            lineitem.ledger = form.cleaned_data['account']
            lineitem.description = form.cleaned_data['store']
            lineitem.cr = form.cleaned_data['amount']
            journal_entry.save()
            lineitem.save()
            messages.success(request, "Split payment successfully updated.")
            return HttpResponseRedirect(reverse('journal:split_payments_show_detail', kwargs={'pk': journal_entry.id}) )
    return render(request, 'journal/split_payments_update.html',{'form': form, 'formset': lineitem_formset, 'journal_entry': journal_entry})



解决了。只是必须使用BaseInlineFormSet。

当您更改为
inlineformset
时,是否检查Django源代码以查看内联表单集是否使用相同的
BaseFormSet
?我的猜测是,他们使用不同的基,可能是BaseInlineFormSet,具有不同的init签名。