[edit]
Since I have removed the new_method = ... and syspar.method.add() lines (this is taken care of by method.save()), the solution that I originally discarded has become DRY, so it is perfectly acceptable.
I do still think it strange that setting self.fields[].initial (as per pyriku's answer) only works if extra > 0, because the simple use case where you don't want a form displayed until an 'add form' button is clicked, must have extra=0 and it should be possible to set initial values for the newly added form.
[/edit]
Disclaimer: I have looked at many answers to related questions, and I have only found one solution that works, but appears crufty to me and not very DRY (4378667) /Disclaimer
I have a modelformset where I set extra to 0, because I only want to display a new form when the user presses "add_method". Everything works fine, except that the newly added forms are empty (desired behaviour: they contain the default value for name that I set in the Method table)
In models.py:
class System(models.Model):
method = models.ManyToManyField(Method)
...
class Method(models.Model):
name = models.CharField()
...
In view.py:
syspar = System.objects.get(id=sys_id)
MethodFormSet = modelformset_factory(Method, form=MethodForm, extra=0)
if request.POST:
if 'add_method' in request.POST:
new_method = Method.objects.create(name='whatever')
syspar.method.add(new_method)
post = request.POST.copy()
post['method-TOTAL_FORMS'] = repr(int(post['method-TOTAL_FORMS'])+ 1)
post['method-2-name'] = 'whatever' # code needed here to get actual value of -2-
methodformset = MethodFormSet(data=post, prefix='method',
queryset=Method.objects.filter(id__in=syspar.method.all()))
I have a problem with the line: post['method-2-name']='' This is awful, because:
- I have already set the value in the db table
- I will need extra cruft to determine the value of '2' for each case
I tried this approach, also tried setting initial (as suggested in answers to some other related questions), but neither worked and both also resulted in non-DRY code.
There must be a better way to do this...