使用内联表单集添加行时出现 MultiValueDictKeyError
MultiValueDictKeyError hen adding lines with inlineformset
我正在尝试使用我之前在表单集工厂中使用的相同方法在内联表单集工厂中添加更多行,但出现错误:
MultiValueDictKeyError form-TOTAL_FORMS'
models.py:
class ttransactions(models.Model):
transaction_type = models.CharField(max_length=10, choices=tx_choices)
description = models.CharField(max_length=50, null=False, blank=False, default='Description')
transaction_date = models.DateField(default=datetime.today, db_index=True)
company = models.ForeignKey(tcompany, on_delete=models.PROTECT, db_index=True)
def __str__(self):
return self.description
class ttransaction_lines(models.Model):
transaction = models.ForeignKey(ttransactions, on_delete=models.PROTECT, db_index=True)
sequence = models.IntegerField()
transaction_type = models.CharField(max_length=6, choices=debit_credit)
ledger_account = models.ForeignKey(tledger_account, on_delete=models.PROTECT, db_index=True)
amount = models.DecimalField(max_digits=14, decimal_places=2, default=0.0)
vat_amount = models.DecimalField(max_digits=14, decimal_places=2, default=0.0)
vat_code = models.ForeignKey(tvat, on_delete=models.PROTECT, blank=True, null=True)
quantity = models.IntegerField(blank=True, null=True)
posted = models.BooleanField(default=True)
forms.py:
class TransactionsForm(forms.ModelForm):
transaction_date = forms.DateField(widget=forms.SelectDateWidget(years=year_range), initial=datetime.today)
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request')
super(TransactionsForm, self).__init__(*args, **kwargs)
class Meta:
model = ttransactions
fields = ['description',
'transaction_date']
class TransactionLinesForm(forms.ModelForm):
class Meta:
model = ttransaction_lines
fields = ['transaction_type', 'ledger_account', 'amount']
class BaseTransactionLinesFormSet(BaseModelFormSet):
def clean(self):
super(BaseTransactionLinesFormSet, self).clean()
# Check errors dictionary first, if there are any error, no point in validating further
if any(self.errors):
return
balance = 0
for form in self.forms:
if form.cleaned_data['DELETE'] == True or form.cleaned_data['DELETE'] == '':
continue
if form.cleaned_data['transaction_type']=='Debit':
balance = balance + form.cleaned_data['amount']
else:
balance = balance - form.cleaned_data['amount']
if balance != 0:
message = 'Transactions not balanced (excluding deleting lines)'
raise forms.ValidationError(message)
TransactionLineFormset = inlineformset_factory(ttransactions,
ttransaction_lines,
form=TransactionLinesForm,
can_order=True, can_delete=True)
views.py
class JournalCreateView(LoginRequiredMixin, CreateView):
template_name = 'accounting/journal.html'
model = ttransactions
formset = TransactionLineFormset
form_class = TransactionsForm
success_url = '/accounting/transaction_list'
def get_form_kwargs(self):
kwargs = super(JournalCreateView, self).get_form_kwargs()
kwargs['request'] = self.request
return kwargs
def get(self, request, *args, **kwargs):
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
formset = TransactionLineFormset(queryset=ttransaction_lines.objects.none())
formset.form.base_fields['ledger_account'].queryset = \
tledger_account.objects.filter(company=request.user.current_company)
return self.render_to_response(
self.get_context_data(form=form, formset=formset))
def post(self, request, *args, **kwargs):
extra_forms = 1
if 'additems' in request.POST and request.POST['additems'] == 'true':
formset_dictionary_copy = self.request.POST.copy()
formset_dictionary_copy['form-TOTAL_FORMS'] = \
int(formset_dictionary_copy['form-TOTAL_FORMS']) + extra_forms
formset = TransactionLineFormSet(formset_dictionary_copy)
return self.render_to_response(
self.get_context_data(form=form,
formset=formset))
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
formset = TransactionLineFormset(self.request.POST)
if (form.is_valid() and formset.is_valid()):
return self.form_valid(form, formset)
else:
return self.form_invalid(form, formset)
def form_valid(self, form, formset):
form.instance.company = self.request.user.current_company
self.object = form.save()
sequence = 1
for line in formset:
line.instance.sequence = sequence
sequence += 1
formset.instance = self.object
formset.save()
return super().form_valid(form)
def form_invalid(self, form, formset):
return self.render_to_response(
self.get_context_data(form=form,
formset=formset))
我在字典复制行的那一行得到了错误。添加行的代码在post函数中添加。我不确定那是否是添加此代码的正确位置。帮助将不胜感激。
如果提交的表单缺少密钥,则会出现此错误。
.get()
方法允许在访问字典中缺少的键时使用默认值。
formset_dictionary_copy['form-TOTAL_FORMS'] = \
int(formset_dictionary_copy.get('form-TOTAL_FORMS', 1)) + extra_forms
看来,表单集没有获取它的所有隐藏值,或者提交了不同的表单。
我会考虑前端解决方案或发送带有添加按钮值的单个初始表单集。
前端/js示例:
https://www.brennantymrak.com/articles/django-dynamic-formsets-javascript
我正在尝试使用我之前在表单集工厂中使用的相同方法在内联表单集工厂中添加更多行,但出现错误:
MultiValueDictKeyError form-TOTAL_FORMS'
models.py:
class ttransactions(models.Model):
transaction_type = models.CharField(max_length=10, choices=tx_choices)
description = models.CharField(max_length=50, null=False, blank=False, default='Description')
transaction_date = models.DateField(default=datetime.today, db_index=True)
company = models.ForeignKey(tcompany, on_delete=models.PROTECT, db_index=True)
def __str__(self):
return self.description
class ttransaction_lines(models.Model):
transaction = models.ForeignKey(ttransactions, on_delete=models.PROTECT, db_index=True)
sequence = models.IntegerField()
transaction_type = models.CharField(max_length=6, choices=debit_credit)
ledger_account = models.ForeignKey(tledger_account, on_delete=models.PROTECT, db_index=True)
amount = models.DecimalField(max_digits=14, decimal_places=2, default=0.0)
vat_amount = models.DecimalField(max_digits=14, decimal_places=2, default=0.0)
vat_code = models.ForeignKey(tvat, on_delete=models.PROTECT, blank=True, null=True)
quantity = models.IntegerField(blank=True, null=True)
posted = models.BooleanField(default=True)
forms.py:
class TransactionsForm(forms.ModelForm):
transaction_date = forms.DateField(widget=forms.SelectDateWidget(years=year_range), initial=datetime.today)
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request')
super(TransactionsForm, self).__init__(*args, **kwargs)
class Meta:
model = ttransactions
fields = ['description',
'transaction_date']
class TransactionLinesForm(forms.ModelForm):
class Meta:
model = ttransaction_lines
fields = ['transaction_type', 'ledger_account', 'amount']
class BaseTransactionLinesFormSet(BaseModelFormSet):
def clean(self):
super(BaseTransactionLinesFormSet, self).clean()
# Check errors dictionary first, if there are any error, no point in validating further
if any(self.errors):
return
balance = 0
for form in self.forms:
if form.cleaned_data['DELETE'] == True or form.cleaned_data['DELETE'] == '':
continue
if form.cleaned_data['transaction_type']=='Debit':
balance = balance + form.cleaned_data['amount']
else:
balance = balance - form.cleaned_data['amount']
if balance != 0:
message = 'Transactions not balanced (excluding deleting lines)'
raise forms.ValidationError(message)
TransactionLineFormset = inlineformset_factory(ttransactions,
ttransaction_lines,
form=TransactionLinesForm,
can_order=True, can_delete=True)
views.py
class JournalCreateView(LoginRequiredMixin, CreateView):
template_name = 'accounting/journal.html'
model = ttransactions
formset = TransactionLineFormset
form_class = TransactionsForm
success_url = '/accounting/transaction_list'
def get_form_kwargs(self):
kwargs = super(JournalCreateView, self).get_form_kwargs()
kwargs['request'] = self.request
return kwargs
def get(self, request, *args, **kwargs):
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
formset = TransactionLineFormset(queryset=ttransaction_lines.objects.none())
formset.form.base_fields['ledger_account'].queryset = \
tledger_account.objects.filter(company=request.user.current_company)
return self.render_to_response(
self.get_context_data(form=form, formset=formset))
def post(self, request, *args, **kwargs):
extra_forms = 1
if 'additems' in request.POST and request.POST['additems'] == 'true':
formset_dictionary_copy = self.request.POST.copy()
formset_dictionary_copy['form-TOTAL_FORMS'] = \
int(formset_dictionary_copy['form-TOTAL_FORMS']) + extra_forms
formset = TransactionLineFormSet(formset_dictionary_copy)
return self.render_to_response(
self.get_context_data(form=form,
formset=formset))
self.object = None
form_class = self.get_form_class()
form = self.get_form(form_class)
formset = TransactionLineFormset(self.request.POST)
if (form.is_valid() and formset.is_valid()):
return self.form_valid(form, formset)
else:
return self.form_invalid(form, formset)
def form_valid(self, form, formset):
form.instance.company = self.request.user.current_company
self.object = form.save()
sequence = 1
for line in formset:
line.instance.sequence = sequence
sequence += 1
formset.instance = self.object
formset.save()
return super().form_valid(form)
def form_invalid(self, form, formset):
return self.render_to_response(
self.get_context_data(form=form,
formset=formset))
我在字典复制行的那一行得到了错误。添加行的代码在post函数中添加。我不确定那是否是添加此代码的正确位置。帮助将不胜感激。
如果提交的表单缺少密钥,则会出现此错误。
.get()
方法允许在访问字典中缺少的键时使用默认值。
formset_dictionary_copy['form-TOTAL_FORMS'] = \
int(formset_dictionary_copy.get('form-TOTAL_FORMS', 1)) + extra_forms
看来,表单集没有获取它的所有隐藏值,或者提交了不同的表单。
我会考虑前端解决方案或发送带有添加按钮值的单个初始表单集。
前端/js示例: https://www.brennantymrak.com/articles/django-dynamic-formsets-javascript