Проверка набора форм с использованием данных из другой формы - PullRequest
0 голосов
/ 29 января 2020

Мне нужно провести некоторую проверку как в форме, так и в наборе форм. Сумма £££ в форме должна равняться сумме сумм в наборе форм.

После долгих поисков я нашел решение, в котором я добавляю пользовательский 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.')

Затем я передаю значение суммы из формы при создании экземпляра набора форм, чтобы можно было использовать это значение при проверке набора форм:

lineitem_formset = LineItemFormSet(form.data['amount'], request.POST)

Это сработало отлично для представления create_new, которое использует formset_factory (). Сегодня утром я написал вид обновления, используя inline_formsetfactory (), но теперь я получаю сообщение об ошибке:

__init__() got an unexpected keyword argument 'instance'

У меня есть только базовое c понимание того, как пользовательский 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})


1 Ответ

0 голосов
/ 29 января 2020

решаемая. Просто нужно было использовать BaseInlineFormSet.

...