I am creating an inventory tracking management application with Django. To avoid having to go through several pages, the screen is split into 3 areas:
- description of the asset (many fields),
- list of depreciating value of the asset (date, value, comment)
- list of “lapse” events (date, flag for present/missing, comment)
This corresponds to 3 tables in the DB. Both lists have a form to enter a new item in the list. The asset is also a form to edit it.
Initially, these were 3 independent <form>
but this made difficult to manage the relationships between the tables because important data was not necessarily submitted. For example, when a new value is created, the asset primary key is not reported because it does not exist in the ValueForm.
Trying to compensate in the template with <input type=hidden …>
was not a reasonable solution because it led to too many duplications in the <form>
.
Consequently, I went for a single <form>
for the whole page. All information (and more than strictly needed for each partial “form”) is then in the POST message. The submit button name is used to tell which part was transmitted.
In the post()
method, sent data is passed to the xxxForms as:
aform = AssetForm(request.POST)
vform = ValueForm(request.POST)
lform = LapseForm(request.POST)
without caring which button has been pressed. This initialises anyway the xxxForm for rendering at end of processing.
When submitting new “value” or “lapse”, form data must be consistent and complete. This means some fields are required. But when user modifies an “asset”, “value” and “lapse” forms are empty or incomplete. Similarly for a “value” regarding “asset” or “lapse”; etc.
Required tests must be disabled for the partial forms not under focus. It is relatively easy to take care of web browser warnings by launching a script to modify the DOM with onclick=
(all sub-form elements are identified with a specific Class=
attribute).
Data for the form of interest are validated by xxxForm.is_valid()
before saving the record. The other yyyForm are passed to render()
in addition to the xxxForm. render triggers yyyForm validations before returning response to user.
Some required data is of course missing (because user focused his attention on xxxForm) and this causes errors to be displayed. These errors make sense when we want to use these forms, but here the yyyForm are only “decorative” data (we don’t forward them to the database or they are totally missing).
I tried to delete yyyForm.errors
but this property is protected against changes.
How can I prevent these errors (which are meaningless in this context) from appearing in the returned HTML page?
Question How to remove error message in django forms? had a promising title but addresses a different issue: permanently remove error.
My case is different: a single template is used to manage logically connected data (from 3 tables) and error messages should be contextually suppressed (not permanently).
Eventually suggest a different approach but I’d like to keep coding to a minimum (presently up to 7 lines per button in a single view).
Well, after a good night sleep, I changed a bit my post()
architecture.
Instead of instantiating systematically the forms, I defer until I test which button was pressed. I can then initialize the specific xxxForm
I need with POST parameters.
Before calling render()
, the “missing” forms are instantiated as xxxForm()
(default instances).
I’ve researched your task a bit, and I think you can easily handle it with CSS and, as you say, focus.
The idea for my answer lies here: Is it possible to change a fieldset’s background-color on input:focus?.
What you can to do:
-
Wrap render of every sub-form in fieldset:
<fieldset> {{subform a|b|c}} <fieldset/>
-
Render every form errors in special , on the last place in field set.
<fieldset> {{subform a|b|c}} <div class="error"> {{ subform.errors }} <div> <fieldset/>
-
pass your css accordingly:
.error { display:none }; input:focus ~ div.error { display:visible };
In this case you are able to see errors on the front end only for the current subform.
3