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.
Related
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.
In short: I have a model with several fields, and on this model is a foreign-key field connecting it to to a User instance. Then, I have a model-form(1) that generates HTML for this model's fields, and that with a custom ModelChoiceField-instance that presents UserProfile-instances instead of User-instances. To validate the submitted information, I have a form (regular form) that validates that a UserProfile-instance was submitted. If it was, I update request.POST (through a copy of it), and validate against a second model-form(2) that exactly mirrors the underlying model.
This all means that I first have to pass a request.POST with a lot of un-validated information into a form that only validates part of it, then updated a copy of a partially validated request.POST, edit it, and then finally validate it again.
Is all of this safe? Is it considered bad practice/unsafe to pass a request.POST with a lot of information into a form that only validates one part of it? Additionally, is it safe to make a copy of a request.POST that is only partially validated - and then update it?
To what degree can you work with objects containing unsafe information, such as request.POST, without it becoming a problem?
Thank you!
I have a form with a bunch of fields but I also pass in values like the current page they submitted the form from and the user, which are hidden fields.
So from what I understand is_valid() will fail because of that. So do I need to run is_valid()?
For example, one of my forms has the line:
self.fields['user'].widget = forms.HiddenInput()
Yes, the form will be validated for all fields - depending upon required/non-required or default etc - for hidden fields as well with respect to provided data.
If you want to save or use the submitted data, you should validate the form using is_valid().
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.
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.