Search code examples
djangoformspython-3.xmodelsmanytomanyfield

How to put data from ManyToManyField to choices in MultipleChoiceField


I have a form:

*# dialogues.forms*

class CreateConferenceForm(forms.Form):
    ...
    participants = forms.MultipleChoiceField(choices=?)
    ...

And I need to put in choices argument instead of "?" data from friends field in this model:

*# persons.models*

class Person(User):
    ...
    friends = models.ManyToManyField(
        'self',
        related_name='+',
    ) 
    ...

How can I do it?


Solution

  • If you're creating an instance of a conference model with your form, you should consider using Django's ModelForm, which is designed to be used in the creation and editing of model instances.

    In either case, you can use a ModelMultipleChoiceField to serve your purpose, which is simply a MultipleChoiceField backed by a queryset for its choices. You can use this field in either a standard Form or a ModelForm.

    To customize the choices based on the request, you can set the queryset in your view.

    For example:

    forms.py

    class CreateConferenceForm(forms.Form):
        # An initial queryset is required, this is overwritten in the view
        participants = forms.ModelMultipleChoiceField(Person.objects.all())
    

    views.py

    def new_conference(request):
        data = request.POST if request.method == 'POST' else None
    
        conference_form = CreateConferenceForm(data=data)
        conference_form.fields['participants'].queryset = my_person.friends.all()
    
        if data:
            if conference_form.is_valid():
                # etc
    
        return render...
    

    Note that it is important for you to set the queryset prior to calling is_valid on the form, since the queryset is used in validation, and prior to sending passing the form to a template, since the queryset is used to generate the choices shown.