DanH
DanH

Reputation: 5818

invalid literal for int() with base 10: '' when saving modified modelformset

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:

  1. Strip any entirely blank rows
  2. Set #id_form-TOTAL_FORMS to the correct value
  3. Reset the name attribute for each input on each row so they are sequential, to prevent gaps due to deletion.
  4. Submits the form.

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:

  1. Have 5 rows
  2. Add values to row 6
  3. Delete any pre-existing row
  4. Click save

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

Answers (1)

Daniel Roseman
Daniel Roseman

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

Related Questions