id,summary,reporter,owner,description,type,status,component,version,severity,resolution,keywords,cc,stage,has_patch,needs_docs,needs_tests,needs_better_patch,easy,ui_ux 12440,"show_hidden_initial needs to ""remember"" initial hidden_initial when rendering form from POST data",Margie Roginski,nobody,"I think there is a ""thinko"" in the way that the show_hidden_initial concept has been implemented, specifically with respect to what happens when a form is rendered from POST data (ie, in the case where there's an error in the form). Sorry if I'm wordy in this description, but understanding this I think requires a conceptual example. I have an app where the user fills out a form that is saved to the database. Multiple users may be working at once, and I have the following not-uncommon situtation: {{{ Joe views object X on his screen Mary views object X on her screen Joe modifies the 'deadline' field of object X and saves it to the db Mary is still looking at her original view of object X which shows the old deadline Mary modifies the 'priority' field of object X and saves it to the db }}} I want the end result to be that Joe has modified the deadline field and Mary has modified the priority field, and this all works fine using show_hidden_initial. By using show_hidden_initial, when Mary's post goes through, hasChanged() returns the priority field, but not the deadline field, and that's exactly what I want. For comparison, if I do not use show_hidden_initial, then when Mary's save is posted, the deadline field looks changed (though she hasn't changed it in her form) due to the fact that it is different from what is currently in the database (ie, what Joe posted). Ok - so all of the above works just fine. Here's the glitch. Suppose Mary posts her form and her post contains an unrelated error (like she unintentionally deletes the contents of the 'name' field and that is marked as requird). When the form is re-rendered with errors, the hidden initial value for the priority field has been reset to whatever she entered for that field. So now when she fixes her error and reposts, the posted priority field no longer looks modified since it is now the same as the posted intial-priority field. The result is that Mary's change to the priority field does not cause has_changed() to return the priority field. This seems inconsistent. IE, it seems like the point of hidden_initial is to allow exactly the fields that the user has changed in the form to be detected as changed, but in this case where there is an error, fields that the user has changed are not being detected as changed. Of course, I am just hypothesizing on the whole purpose of this hidden initial stuff - I don't believe it is documented, but I have never the less fouund it extremely useful. I think that the way to fix this is to populate the initial inputs that are sent to the client with saved hidden initial data, if it exists. In other words, once the hidden initial data is taken from the object during the GET, when the form is recreated during a POST, if the intial data is in the POST, the new hidden initial data should be taken from the initial data in the post, not from data posted by the user. Here's what I've added which seems to work for me. In forms/forms.py: Original code in as_widget() {{{ if isinstance(self.field, FileField) and self.data is None: data = self.form.initial.get(self.name, self.field.initial) else: data = self.data }}} My changes to as_widget() {{{ if isinstance(self.field, FileField) and self.data is None: data = self.form.initial.get(self.name, self.field.initial) else: if only_initial: hidden_initial = self.form.hidden_initial.get(self.name) if hidden_initial != None: data = hidden_initial else: data = self.data else: data = self.data }}} I'm not as familiar with the django code that initializes the form, so I'm quite sure where the appropriate place to initialize the hidden_initial dict is, so I curently have it in my own task form, like this: {{{ class CommonForm(forms.ModelForm): def __init__(self, *args, **kwargs): super(CommonForm, self).__init__(*args, **kwargs) data = kwargs.get(""data"") if data: self.hidden_initial = {} for fieldName in self._meta.fields: fieldInitialData = data.get(self.add_initial_prefix(fieldName)) if fieldInitialData != None: self.hidden_initial[fieldName] = fieldInitialData }}} Maybe this would go in BaseForm()? Anyway, sorry for this being somewhere between a bug report and a patch. This is not ready for primetime as a patch, but since I understand it pretty well now, I thought I would pass on as much of what I understand as I could. I just don't have the time it would take to turn it into a real patch with running tests and all. But if someone else thinks it's important, I wanted to give enough info for them to run with it. ",,closed,Uncategorized,1.1,,duplicate,,,Accepted,0,0,0,0,0,0