The ModelForm api is very similar to that of the regular Form. The advantage is that you now get model validation in addition to conveniences like default widgets, the instance kwarg, and the save method.
Put the fields in the exclude and add them the way you are doing in the original __init__.
Clean them the same way.
Then, you can override the save method: you can call super() to get the object back and deal with the data in cleaned_data however you want.
# regular fields, not based on bools
model = Order
exclude = ('work_type', 'vendor', 'note')
# or fields = (...other fields )
super(OrderDetailForm, self).__init__(*args, **kwargs)
self.fields['work_type'] = forms.ChoiceField(
self.fields['vendor'] = forms.ModelChoiceField(
empty_label="Choose a vendor",
self.fields['note'] = forms.CharField(widget=forms.Textarea)
# I never call super() in clean .. do I? .. hmmm
# maybe I should or is sth magic going on?
# data = self.cleaned_data
# let's call super though
data = super(OrderDetailForm, self).clean()
if 'note' in data:
if len(data['note']) < 50:
# I raise a validation error so .is_valid() comes back False
# form.errors happens magically ...
raise forms.ValidationError("Not long enough ...")
def save(self, *args, **kwargs):
data = self.cleaned_data
# maybe do some stuff here
# commit=True or commit=False could be important
order = super(OrderDetailForm, self).save(*args, **kwargs)
if 'note' in data:
order.note = data['note']
# ... do other stuff
# probably ...
# respect how model forms work.
So how do just I add a model field to fields under __init__? Can I just do something like self.fields.append('note')? It seems like fields is still a tuple, not a dictionary.
Can you show me an example with my code in your answer?
updated with code. Why do you think fields is a tuple?
In the regular Form, you aren't appending to the fields attr but rather assigning values to its keys.