Reputation: 5818
I have a modelform formset allows the user to add empty rows, delete existing rows via AJAX and rearrange the rows using jQuery sortable.
Both the add/rearrange just set values on the form, and are saved as part of the formset.save()
.
The add new row mechanism generates a clone of the last existing row, and generates the correct input names e.g.: form-0-id
.
As mentioned, the delete operation calls AJAX and then removes the row from the DOM on success.
The rearrange sets a hidden weight input which is part of the model.
Upon pressing Save, the following happens in order:
As far as I can tell from console.log
the above steps are all carried out as expected, however the one case where I get an error is if I:
And I get invalid literal for int() with base 10: ''
Specifically this error is firing from:
lib/python2.7/site-packages/django/db/models/fields/__init__.py in get_prep_value
return int(value) ...
Local vars:
Variable Value
self <django.db.models.fields.AutoField: id>
value u''
I don't quite understand why this is failing, I thought the entire point of an auto field was to set a value if it isn't already.
I'm also somewhat confused, since the entire form works fine for adding new rows, as long as a deletion doesn't happen before the entire form is saved.
Is the form somehow remembering the different input name attributes and trying to update an existing record rather than save a new one?
Here's the POST data from the failed request:
Variable Value
form-INITIAL_FORMS u'6'
form-TOTAL_FORMS u'3'
form-MAX_NUM_FORMS u''
form-0-id u'38'
form-0-weight u'0'
form-0-disk_space u'1'
form-0-price_per_month u'1'
form-0-embedded_html u'1'
form-1-id u'45'
form-1-weight u'3'
form-1-disk_space u'2'
form-1-price_per_month u'2'
form-1-embedded_html u'2'
form-2-id u''
form-2-weight u'6'
form-2-disk_space u'3'
form-2-price_per_month u'3'
form-2-embedded_html u'3'
So it seems to be failing on form-2-id
trying to set the field value, rather than allow auto to do it's job.
Below is POST data from a successful submission however, where I simply loaded the form, added a new row and then saved.
Variable Value
form-INITIAL_FORMS u'2'
form-TOTAL_FORMS u'3'
form-MAX_NUM_FORMS u''
form-0-id u'38'
form-0-weight u'0'
form-0-disk_space u'1'
form-0-price_per_month u'1'
form-0-embedded_html u'1'
form-1-id u'48'
form-1-weight u'1'
form-1-disk_space u'2'
form-1-price_per_month u'2'
form-1-embedded_html u'2'
form-2-id u''
form-2-weight u'2'
form-2-disk_space u'3'
form-2-price_per_month u'3'
form-2-embedded_html u'3'
As far as I can tell everything is the same as the failed request, with the new row having a blank id.
Full traceback: http://pastebin.com/AvegYgJA (was too big for SO)
Copy and Paste mode traceback http://pastebin.com/9R68M6YX
SOLUTION:
As per Daniel Roseman's answer below, I simply needed to set id_form-INITIAL_FORMS
to match the number of updated rows. Rather than decrement the initial forms on deletion, I added the following to my JS before submitting the form:
$('#id_form-INITIAL_FORMS').val(this.form.find('span.row-id input[value!=""]').length);
Thus solving the problem forever!
Upvotes: 2
Views: 826
Reputation: 599876
I believe the problem is that your JS doesn't modify the value of form-INITIAL_FORMS
when you delete the form. Because of that, Django believes that your new form is actually an update, rather than an add, and tries to modify an existing db row - but of course you have a blank ID for that row. Try decrementing form-INITIAL_FORMS
in the delete.
Upvotes: 1