4

I need to set initial data to formset with ManyToMany field.

Usually i'm doing like this when there is no ManyToMany field in forms of my fomset:

PersonFormSet = forms.formsets.formset_factory(NickName, can_delete=True)
init_data = [{'name':'Vasya pupkin','nick':'Vasya'}, 
             {'name':'Vasyapupkin','nick':'Petya'}]

nick_formset = PersonFormSet(initial=init_data)

But now I need to set ManyToMany field initial data and tried something like this:

NickNameFormSet = forms.formsets.formset_factory(NickName, can_delete=True)
init_data = [{'name': 'Vasya Pupkin',
              'nick': {'Vasya':'selected',
                       'Petya':'notselected'}}]

nick_formset = NickNameFormSet(initial=init_data)

But it doesn't works.

How can I pass initial data to Formset so it render my widget like this:

<select multiple="multiple" name="person_set-0-nickname" id="id_person_set-0-nickname">
    <option value="1" selected="selected">Vasya</option>
    <option value="2">Petya</option>
</select>

Note: I'm using only Forms, and Formsets of Django. There is no Django models. I can actually define it but it's empty, I'm using NoSQL.

Stan
  • 8,710
  • 2
  • 29
  • 31
Pol
  • 24,517
  • 28
  • 74
  • 95
  • Actually i found solution. But it was more than one year ago. Dont remember it. I can look for it for you. – Pol Sep 26 '12 at 18:12

3 Answers3

1

You should provide a list of pk as initial data for your ManyToMany relation instead of a dict.

Take a look at this thread, it might helps you.

Community
  • 1
  • 1
Stan
  • 8,710
  • 2
  • 29
  • 31
0

You can use the __init__ function to pre-populate initial data.

Here's what I used for a similar problem:

class MyUpdateForm(forms.ModelForm):

    def __init__(self, *args, **kwargs):
        super(MyUpdateForm, self).__init__(*args, **kwargs)
        self.initial['real_supplements'] = [s.pk for s in list(self.instance.plan_supplements.all())]

Instead of using self.instance.plan_supplements.all() in my example, you can provide any Queryset.

SaeX
  • 17,240
  • 16
  • 77
  • 97
0

Like this:

class CustomFormSet(BaseInlineFormSet):
    def __init__(self, *args, **kwargs):
        kwargs['initial'] = [
            {'foo_id': 1}
        ]
        super(CustomFormSet, self).__init__(*args, **kwargs)

the foo_id depends on the value that you're selecting for which field on the model relationship

You have to change also the has_changed method on the form class in order for the it to know that the initial values are "changed" to be taken in account when saved:

class CustomForm(forms.ModelForm):
    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(starnpc_class, self).has_changed()
        return bool(self.initial or changed_data)
Julio Marins
  • 10,039
  • 8
  • 48
  • 54