1

[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...

Community
  • 1
  • 1
John Peters
  • 1,177
  • 14
  • 24

1 Answers1

1

Probably you will need to override the __init__() method of that form for setting the initial values that you want. Something like:

def __init__(self, *args, **kwargs):
    super(MethodForm, self).__init__(*args, **kwargs)
    self.initial['field'] = 'value'
pyriku
  • 1,251
  • 7
  • 17
  • I don't see how that could work, because the `ModelFormSet` instance (which uses `MethodForm`) is created *before* the new `Method` object is created, so where would the `__init__` method get `'value'` from? – John Peters Jul 25 '12 at 10:46
  • I understand now - the way I created the new Method in the above code was wrong. Setting self.initial['field'] did not work for that case. I completely re-wrote the view (using a custom save() method in the MethodForm and now it self.initial works. – John Peters Jul 30 '12 at 00:26
  • Oops - I was too quick marking this answer correct. In the mean time I had set extra to 1. Now that I have set extra back to 0 setting initial values does not work anymore... – John Peters Jul 30 '12 at 05:19