Reputation: 327
I've just started playing with formsets. No idea what I'm doing at the moment. I've got to the point where a form with formset is being saved to the database. However, if nothing is selected for the required field "ledger" then validation still passes, and Django throws up "Key error".
My forms.py:
class JournalEntryForm(forms.Form):
date = forms.DateField(widget=DateTypeInput())
description = forms.CharField(required=False)
class LineItemForm(forms.Form):
ledger = forms.ModelChoiceField(queryset=Ledger.objects.all())
description = forms.CharField(required=False)
project = forms.ModelChoiceField(queryset=Project.objects.all(), required=False)
cr = forms.DecimalField(decimal_places=2, required=False)
dr = forms.DecimalField(decimal_places=2, required=False)
My function in views.py. I've marked line 33 which is the line where the "key error" occurrs.
@login_required
def entries_new(request):
# Takes form and returns form set. So we now have a form set.
LineItemFormSet = formset_factory(LineItemForm, extra=2)
if request.method == 'POST':
journal_entry_form = JournalEntryForm(request.POST)
lineitem_formset = LineItemFormSet(request.POST)
if journal_entry_form.is_valid() and lineitem_formset.is_valid():
q0 = JournalEntry(user=request.user, date=journal_entry_form.cleaned_data['date'], type="JE")
q0.save()
for lineitem_form in lineitem_formset:
q1 = LineItem(
journal_entry=q0,
ledger=lineitem_form.cleaned_data['ledger'], #<---- This is line 33 referenced in the error
cr=lineitem_form.cleaned_data['cr'],
dr=lineitem_form.cleaned_data['dr'],
project=lineitem_form.cleaned_data['project'],
)
q1.save()
messages.success(request, "Journal entry successfully saved.")
return HttpResponseRedirect(reverse('journal:entries_show_all') )
else:
journal_entry_form = JournalEntryForm()
lineitem_formset = LineItemFormSet()
context = { 'journal_entry_form': journal_entry_form, 'lineitem_formset': lineitem_formset, }
return render(request, 'journal/entries_new.html', {'journal_entry_form': journal_entry_form, 'lineitem_formset': lineitem_formset})
The error I get in my browser:
KeyError at /journal/entries/new/
'ledger'
Request Method: POST
Request URL: http://localhost/journal/entries/new/
Django Version: 3.0
Exception Type: KeyError
Exception Value:
'ledger'
Exception Location: C:\Users\Philip\CodeRepos\Acacia2\Journal\views.py in entries_new, line 33
Python Executable: C:\Users\Philip\CodeRepos\Acacia2\venv\Scripts\python.exe
Python Version: 3.8.0
Python Path:
['C:\\Users\\Philip\\CodeRepos\\Acacia2',
'C:\\Users\\Philip\\AppData\\Local\\Programs\\Python\\Python38-32\\python38.zip',
'C:\\Users\\Philip\\AppData\\Local\\Programs\\Python\\Python38-32\\DLLs',
'C:\\Users\\Philip\\AppData\\Local\\Programs\\Python\\Python38-32\\lib',
'C:\\Users\\Philip\\AppData\\Local\\Programs\\Python\\Python38-32',
'C:\\Users\\Philip\\CodeRepos\\Acacia2\\venv',
'C:\\Users\\Philip\\CodeRepos\\Acacia2\\venv\\lib\\site-packages']
Server time: Thu, 26 Dec 2019 20:42:45 +0000
Upvotes: 0
Views: 168
Reputation: 327
So after some digging, it turns out that Django does not validate any empty formsets. I added the following init to my form and now I get a nice formerror if an empty formset is submitted:
class LineItemForm(forms.Form):
ledger = forms.ModelChoiceField(queryset=Ledger.objects.all(),)
description = forms.CharField(required=False)
project = forms.ModelChoiceField(queryset=Project.objects.all(), required=False)
cr = forms.DecimalField(decimal_places=2, required=False)
dr = forms.DecimalField(decimal_places=2, required=False)
# This init disallows empty formsets
def __init__(self, *arg, **kwarg):
super(LineItemForm, self).__init__(*arg, **kwarg)
self.empty_permitted = False
I have no idea what the init does (arg, kwargs and super are all still a mystery to me). I copied it from another page. It works though.
Upvotes: 1
Reputation: 959
Source : Django documentation
Default value for ModelChoiceField
is None
, even if you specified the queryset
attribute. If the form is valid, to me it means than None in Ledger.objects.all()
is True
! Are you sure you do have Ledger
objects in your database?
Upvotes: 0