passing initial data to a formset, doesn't show data_changed as true / does not save data
See original GitHub issueNot sure if this is a deeper problem with Django ModelForms, or just this package.
If I have a ModelFormSetView, to add Persons objects to a Trip object. I want to add some initial data to the forms, default names for each person, “Person 1”, “Person 2” etc.
class AddPersonsFormSetView(ModelFormSetView):
model = Person
template_name = 'AddPersons.html'
extra = 1
success_url = '/trip/%s/expense/add/'
def get_formset_kwargs(self):
kwargs = super(AddPersonsFormSetView, self).get_formset_kwargs()
num_persons = self.kwargs['num_persons']
## inital data will give the name Person <increment>
initial = [
{ 'name' : "Person %s" % i , 'trip' : self.kwargs['trip_id'] } for i in range( 1, int(num_persons)+ 1)
]
kwargs.update({'initial': initial })
return kwargs
Now if I change the values in the form, it saves correctly. If I leave the default values as they are, the PersonForm generated by the factory does not see the data_changed() as True, so doesn’t save anything.
I can work around this by creating the form, overriding the has_changed method, and specifying it in the get_factory_kwargs() method of the AddPersonFormSetView but this isn’t an obvious solution until you step through the code. It doesn’t not feel seem correct behaviour to ignore default values.
class PersonForm(ModelForm):
class Meta:
model=Person
def has_changed(self):
"""
Overriding this, as the initial data passed to the form does not get noticed,
and so does not get saved, unless it actually changes
"""
changed_data = super(ModelForm, self).has_changed()
return bool(self.initial or changed_data)
class AddPersonsFormSetView(ModelFormSetView):
...
...
def get_factory_kwargs(self):
kwargs = super(AddPersonsFormSetView, self).get_factory_kwargs()
kwargs['form'] = PersonForm
return kwargs
Issue Analytics
- State:
- Created 9 years ago
- Comments:8
Top GitHub Comments
Happened to me too. The correct way to fix this is to not pass the
initial
argument to the form in case we’re binding the form (POST).Agreed