24👍
After studying the Django source further, with helpful hints from Florian’s answer, I can report that has_changed
and changed_data
do work as described in my question as long as the form has a way to get the initial data to compare the new data against.
So the question is, how does a form created from POST data know what the initial values of the GET form were? The short answer is it doesn’t — unless you tell it somehow. There are two ways to tell it:
-
Via the
initial
keyword argument to the form and/or theinitial
keyword arguments to the fields, exactly the same way you tell the GET form the initial values. NOTE: If you do this, it’s up to you to make sure you use the same values for your GET and POST forms. This is the only truly reliable way to do it, since you directly control what the initial values are. -
You let Django do the work of remembering the initial values from your GET by setting the
show_hidden_initial
keyword argument toTrue
for each applicable field. For these fields, Django renders a hidden input element with the initial value into the GET form’s HTML. Later, when you callhas_changed
orchanged_data
on the POST form, for any field withshow_hidden_initial
asTrue
Django will automatically get the initial values from the hidden input elements in the POST data (superseding any initial values frominitial
form or field arguments). NOTE: as with anything relying on POST data, this approach is ultimately unreliable, since the values for the hidden inputs could still be changed despite being hidden.
7👍
You can rely on those methods on two conditions:
- You pass the initial data dict to the form constructor during post requests too.
- You don’t use fields with
show_hidden_initial=True
. (The issue with such fields is that a user can submit the initial value used for comparison too and as such it wouldn’t be trustworthy.)
- [Django]-How to mix queryset results?
- [Django]-How to get getting base_url in django template
- [Django]-Form with CheckboxSelectMultiple doesn't validate
1👍
Here is a piece of code that does what @Ghopper21 is suggesting. To get the initial data, I use the values() function on the QueryDict. It returns a dictionary containing the data belonging to the object. An important caveat is that I haven’t checked how it handles foreign key references.
saveStudentView(request,studentID):
existingData = Student.objects.filter(id=paperID).values()[0]
form = StudentForm(request.POST)
if form.is_valid():
form = StudentForm(request.POST, initial=existingData)
if not form.has_changed():
//Tell the user nothing has changed
else:
//Do other stuff
- [Django]-Pagination in Django-Rest-Framework using API-View
- [Django]-Querying django migrations table
- [Django]-How to get username from Django Rest Framework JWT token