Opened 6 years ago

Closed 6 years ago

#20333 closed New feature (wontfix)

Problems with BaseInlineFormSet.validate_max

Reported by: Michael Angeletti Owned by: nobody
Component: Forms Version: master
Severity: Normal Keywords: formsets, validation
Cc: Michael Angeletti Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no


I've noticed a couple problems with the validation of BaseInlineFormSet.max_num (when using the new BaseInlineFormSet.validate_max feature. The first one is way more important, but the second one is a nuisances as well. Both can be reproduced with a normal inline formset. I am using master @ 1267d2d9bc.

1) User can click back in their browser and exceed max_num after maxing out a formset and submitting the form.


If I click "submit" on a form that has a max_num of 1, then hit back and repopulate the same form again, clicking "submit" again, another record will be created, and this is boundless. I can take a formset with max_num set to 1 and create 500 records. I would venture to guess that you could even exceed the hard stop of 1000 by doing this.

2) Attempting to delete existing records when max_num is already exceeded results in a validation error, even when not adding or editing records.


When validate_max is in effect, but max_num has already been exceeded (i.e., if I turn down max_num after users create objects) Django doesn't allow the user to even delete the existing records, meaning there is no way to remedy the situation. (see - I merely checked the "delete" checkbox without adding any new "uploads" or editing the existing ones)

Change History (3)

comment:1 Changed 6 years ago by Michael Angeletti

Cc: Michael Angeletti added
Component: UncategorizedForms
Keywords: formsets validation added
Type: UncategorizedBug

comment:2 Changed 6 years ago by Carl Meyer

Type: BugNew feature

I think these are really separate issues, that would be fixed and considered separately, and thus are better tracked in separate tickets. I've opened #20403 to track the second, and am re-purposing this ticket to track just the first.

Regarding the first issue, I don't believe it is a bug in formset validation; the validation of an individual formset works as intended and as documented: you can't submit more forms in a single formset than the max, if validate_max is True.

The issue you're seeing is that formsets don't prevent the same user submitting the same formset (which, taken individually, passes validation) repeatedly. I think this pretty much has to be the application developer's responsibility; I don't see how formsets could handle this generically.

Model formsets are a special case of this, because unlike a plain formset they do know something about the final destination of their data; in theory the model formset validation could check the database to see whether the number of "existing" rows submitted in the formset match the number in the database, or whether someone added more to the database in the interim, making this formset "out of date" (which means that saving its new rows might result in more total rows in the database than the intended maximum).

I don't think model formsets should do such validation by default, due to the added complexity and database activity, but this could be further discussed. This is parallel to the general issue of stale forms (I load an edit form, you load the same edit form and submit it, I submit mine later on and overwrite your changes without ever seeing them), which Django also does not attempt to solve out-of-the-box.

I'm leaving this open for now as a feature request for that additional model formset validation, but my inclination is that it should be closed wontfix.

comment:3 Changed 6 years ago by Russell Keith-Magee

Resolution: wontfix
Status: newclosed

I agree with Carl - this isn't a bug in formsets. If anything it's a bug in model version management. The situation I can see this arising is where User A and User B both retrieve a page with a formset, then User A submits the form, and then user B submits the form, you end up with 2 inlines being created. However, the problem doesn't lie with the formset -- it's with the fact that User B has been able to submit an update for an object that has already been modified.

Note: See TracTickets for help on using tickets.
Back to Top