I’m using an inline formset with some javascript to add more forms with a button press.
One of the views keeps trying to validate blank, dynamically added forms and is triggering “this field is required” warnings. I have no problem with the initial 2 forms in the formset that are created via extra=2, they can be blank without causing errors.
OrderLineItem has a foreign key to Order
#views.py
def my_new_form_view(request):
OrderFormSet = inlineformset_factory(Order, OrderLineItem, extra=2, can_delete=False,
formfield_callback=make_custom_datefield, form=OrderLineItemForm,
formset=OrderLineFormSet)
if request.method == 'POST':
form = OrderForm(request.POST)
order_formset = OrderFormSet(request.POST, prefix="lineitem")
if form.is_valid() and order_formset.is_valid():
new_order = form.save()
new_order_formset = order_formset.save(commit=False)
order = Order.objects.get(pk=new_order.pk)
for form in order_formset.forms:
if form.has_changed():
new_f = form.save(commit=False)
new_f.order = order
new_f.save()
return redirect() #go to details
else:
form = OrderForm()
order_formset = OrderFormSet(prefix='lineitem')
–
#forms.py
class OrderLineFormSet(forms.models.BaseInlineFormset):
def clean(self):
#just a clean method to look for duplicates
class OrderLineItemForm(ModelForm):
#just some callbacks, widget setttings, and the Meta
–
#html
<!-- form stuff above this -->
{{ order_formset.management_form }}
{{ order_formset.non_form_errors }}
{% for form in order_formset %}
<div class="line_item">
<p> </p>
{{ form.non_field_errrors }}
{% for field in form.visible_fields %}
<div class="field">
{{ field.errors }}
{{ field.label_tag }}
{{ field }}
</div>
{% endfor %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
</div>
{% endfor %}
$('#add_more').click(function() {
cloneMore('div.line_item:last', 'lineitem');
});
–
#js CloneMore
function cloneMore(selector, type) {
var newElement = $(selector).clone();
var total = $('#id_' + type + '-TOTAL_FORMS').val();
newElement.find(':input').each(function() {
var name = $(this).attr('name').replace('-' + (total-1) + '-','-' + total + '-');
var id = 'id_' + name;
$(this).attr({'name': name, 'id': id}).val('').removeAttr('checked');
});
newElement.find('label').each(function() {
var newFor = $(this).attr('for').replace('-' + (total-1) + '-','-' + total + '-');
$(this).attr('for', newFor);
});
total++;
$('#id_' + type + '-TOTAL_FORMS').val(total);
$(selector).after(newElement);
}
I’ll add more code on request, this is just already a lot of clutter.
Something with the javascript added forms seems to be triggering the .has_changed() despite being blank. What am I missing that isn’t allowing the blank forms?
Solution
One field in the formset has a default. When I clone a form it clears all inputs. Django sees the removal of the default value as a change and triggers the is_changed() and validates the form.
Check the generated form code in something like Firebug. If any field has a value, the form will be treated as “filled out”, in the sense that it will then attempt validation on it. Even if you have hidden fields with default values, this can occur. For the form to be disregarded, it must be completely blank on submission.