What triggers form validation for a Django formset? - django

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.

Related

Dynamic read-only field in Django Admin

In Django Admin for a Model I want all fields to be:
editable on creation
some of them on updating ( based on the instance fields values on creation).
For example:
2-1. If attribute a has a value, the fields corresponding to attributes c and b to be readonly
2-2. If attributes are empty after creation, should not be editable on updating
I know that for normal forms there is the Field disabled attribute.
I know I need to overwrite Admin form, but I don't have an idea, to know is created or update when form is initialized.
Usually I get the value using clean(), but here I need to get them on initialization in case of updates.
So it is like this:
You can create custom FORMS see here https://docs.djangoproject.com/en/1.8/ref/contrib/admin/#django.contrib.admin.ModelAdmin.form
After that you can add your logic of which form to use by overriding the get_form method. see here https://docs.djangoproject.com/en/1.8/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_form
However you need to make sure your DB will accept the partially submitted data. You can DROP NULL on the specific columns.

Django ManyToMany Field in form - unnecessary database calls?

In a django form that has a manyToMany field - is there a database call to retrieve each object in the list when you're adding a new entry? Is this necessary/ wasteful?
For example:
class MyForm(ModelForm):
likes = forms.ModelMultipleChoiceField(queryset=Videos.objects.all())
....
the form is submitted with a list of project id's. within the clean() method likes becomes a list of Video objects. However you can do:
self.instance.likes.add() ...without ever having to get the objects.
...
is it wasteful that the objects are being retrieved first before updating the relationship? if not, why?
I would say that every time you save the form, it would be evaluating the queryset you passed it to check that each ID is within that queryset. if you wish to optimize the behavior, try subclassing ModelMultipleChoiceField and removing the checks/making them more streamlined.

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.

django inlineformset_factory, view changed fields on save

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.

Django ModelForm Instantiation after Form Creation

I have a form that consists of a response for each entry in another model. At the time the form is generated the response to each item may or may not exist. I need a form that allows me to update the response if it exists and create it with the form post data if it doesn't exist.
Currently I am iterating through a range and creating my forms with the post data:
forms = [SpecialNoteForm(request.POST, prefix=str(x), ) for x in rang(1,3)]
I am doing this because I don't know how else to access the form data cleanly in order to identify the object that the form should be instantiated with. I tried doing something like this after the forms list was created because i can then access the form data:
for form in forms:
try:
instance = SpecialNote.objects.get(flag=form["flag"].data, host=form["host"].data)
form.instance = instance
form.save()
The errors on the form persist after I do this, however. I need a way of accessing the data I need to instantiate the object at the time of form creation or a way of re-evaluating the form after i've attached an instance to it.
EDIT
I ran into the same problem with model formsets as I did with my initial approach--I don't know how to instantiate the forms while at the same time allowing for intial values on forms that don't have an instance. I don't want to create all of the model instances before hand because it is import whether or not the user has submitted these with the required fields filled in.
My current approach is still using the model forms:
forms = []
for n in form_range(request.POST): # calculates number of forms based on post data
try:
instance = SpecialNote.objects.get(flag=request.POST.get('%s'%n+'-flag'), host=request.POST.get('%s'%n+'-host'))
except:
instance = None
forms.append(SpecialNoteForm(request.POST, prefix=str(n), instance=instance))
for form in forms:
if form.is_valid():
form.save()
In summary, the problem with formsets is I don't know how to properly instantiate the forms without having them be queriable, i.e. already in the database. The problem with using regular model forms and a prefix is that getting the objects that i need to instantiate them with is messy (as you can see from my current approach). I'm looking for a solution to either of these two problems.
Multiple identical model forms on one page is what model formsets are for. They should take care of all of those issues.