django inlineformset_factory, view changed fields on save - django

I am creating some custom validation, that on save checks if certain fields values have changed.
On POST, is there a way in the view that I can check what fields have changed for that formset?
I am currently looping through the formset and am able to view individual field values, so I could compare them to a query. It just seems to be a bit more than necessary considering the formset doesn't go through the save process if nothing has changed.
Any help is appreciated.

Add a method to your formset:
def has_changed()
return all([form.has_changed() for form in self.forms])
Similarly, the form also documents the changed_fields, which you can concatenate in your formset.
I don't think formset.save() blindly overwrites all entries into the db. It checks the changed forms, which I think is available in formset.changed_forms and it updates only those rows in the db.

Related

What Is Can Order In Django Formsets Actually For?

I've spent a fair amount of time the last day or so exploring the can order field with Django Formsets but I can't for the life of me actually figure out what it's for. Apparently it doesn't update the database...and it does put an order number field with the form....but beyond that what is it for?
I can't find any useful documentation on how to actually use this field. Do I have to write Javascript in order to get this field to do anything actually meaningful?
I get the delete option...and you have to add code in to delete the record...So I guess I'm to take it the same is required for the can_order field?
Sorry if this is a silly question but I've spent more time trying to figure this out than what would be reasonable by now.
All it does is add an integer ORDER field to each form in the formset so you can manually order them after instantiating the formset. Just imagine your forms have a title with this imaginary formset data. You can use ordered_forms to iterate through each form, inspect its cleaned_data, and change it's ordering before returning the form in your context.
formset = ArticleFormSet(data)
if formset.is_valid():
for form in formset.ordered_forms:
if form.cleaned_data['title'] = 'My form title'
form.cleaned_data['ORDER'] = 2
form.save()
The can_order adds a field to the formset, just like the can_delete does. You do not NEED JavaScript, but you can use it, for example if you use JavaScript to drag and drop the forms in the formset. You can sort them and then you can change the name attribute to reflect the new order by accessing the specific form by using it's id in your JavaScript.
The can_order IS like the can_delete, in that the can_order` will simply add the following to each of the forms in your formset, where N = 0, 1, 2, 3, 4...
<input type="number" name="form-N-ORDER" id="id_form-N-ORDER">
What can you do with this without JavaScript? Add an order field to your model, and then you can get the forms order in your post, and set the order field of your model to equal that.

django: save one field of a formset at a time

My django app connects to a sql server database. On my template I have an editable datatable/formset. Whenever a user edits a field and hits enter, I want only the edited field to be saved. As far as I know AJAX is the only approach to do this, especially if you want the value of the edited field to be the only one transfered to the server. Let's put this case aside for now and accept transferring all data of the formset at once.
Also, the formset is based on a sql server view that includes calculated values. Hence, executing formset.save() will raise an error. Instead I have to use the underlying table to save the modified value. What would be best practice to identify the changed field and save only this one?
Let's say the underlying table is costsperdiem that corresponds to a model in my django app and 'costs' is the name of the editable field I want to save then my approach is as follows:
check if the formset is valid
loop through the forms of the formset using changed_data to seek for the modified field
using a model instance to filter for the modified record
pass the modified value to the model
save the model
which looks like this in code:
formset = FormSet_CostsPerDiem(request.POST)
if formset.is_valid():
for f in formset.forms:
if 'costs' in f.changed_data:
val2save=f.cleaned_data['costs']
id=f.cleaned_data['id_costsperdiem']
rec2save=costsperdiem.objects.filter(pk=id)
rec2save.costs=val2save
rec2save.save()
What is best practice to do something like this?

Django formset - validate one of the forms, not all

I have a formset that generates two forms that have different initial values. When the user submits the form, they're only going to fill out one of them, not both. These initial values get populated in the view, which (I think) means FormSet can't figure out if they've changed or not, so default validation fails. But really, all I care about is if one of them is valid. I'd like to take that valid form and process it. What's the best way to go about this?
Not only formset.is_valid() exists, but also
for form in formset.forms:
if form.is_valid():
..
should work.

Easiest way to save Django´s formwizard form_list in DB?

I have created multiple sub-forms from one model to use the FormWizard in Django.
Confusing is the saving part. Once the user finished the form, I wanted to save the information in the DB. This is fairly simply with one form, where I can say
one_form_from_model.save()
But could I do it when I get a form_list returned. I read some postings but they did not make any sense to me.
Can I clean the data
form.cleaned_data for form in form_list]
and then go through every form? But then I would need to know in which form I am to find the right fields. Isn´t there any easier way to do it?
Thank you for your advice!
Try something like this:
instance = MyModel()
for form in form_list:
for field, value in form.cleaned_data.iteritems():
setattr(instance, field, value)
instance.save()

What triggers form validation for a Django formset?

I have a from based on ModelForm and use formset_factory to create a formset based on two dictionaries. There is also one extra form.
In my view, I use the formset JS plugin and I delete the two forms with data. When I POST the remaining empty extra form, it fails validation because of a required field.
I don't understand why that form is being validated. Its changed_data list is empty. It is returned with empty_permitted = False (and I'd like to know why that is), but even after I change it to True in the debugger, it is validated.
So what is triggering validation and how can I modify it?
I would also be interested to know where data like the initial data is stored. Is that somewhere in my view where I am not seeing it?
The template management form has a counter called INITIAL_FORMS. The formset plugin for adding and deleting forms does not distinguish between initially populated forms and forms it adds. When a form is deleted, if it was initially populated, then INITIAL_FORMS should be decremented.
This can be implemented by including a template variable which flags forms which are initially populated. In the removed function of the formset plugin, if one of these flagged forms is being deleted, then decrement INITIAL_FORMS.