Search code examples
djangoformscheckboxmany-to-manypreferences

Django persist ModelMultipleChoiceField selections


I have a ModelMultipleChoiceField that allows a user to select one or more of a set of my "community" model (akin to a user joining a subreddit). When the user reopens the page to select communities, there are no checkboxes on the fields that the user has selected before. I would like to make it so that previously selected communities stay with check boxes, and therefore when the user hits submit their previous choices won't be forgotten if they don't reselect the previous choices.

Here is my form:

class CustomChoiceField(forms.ModelMultipleChoiceField):
    def label_from_instance(self, obj):
        return obj.name

class CommunitySelectForm(forms.ModelForm):
    community_preferences = CustomChoiceField(queryset=Community.objects.all(), widget=forms.CheckboxSelectMultiple)

    class Meta:
        model= UserQAProfile
        fields = ['community_preferences']

And here is my template:

<div class="col-sm-8 input">
  <form method="post" enctype='multipart/form-data'>
      {% csrf_token %}
      {{ form.as_p }}
      <input class="btn btn-submit pull-left"  type="submit" value="Choose Communities" />
  </form>
</div>

The UserQAProfile model has a ManyToMany field to store the preferences:

community_preferences = models.ManyToManyField(Community)

Here is the view that initializes the form:

def joinCommunities(request, user_id):
    user_ob = get_user_model().objects.filter(id=user_id).first()
    full_user_profile = UserQAProfile.objects.filter(user=user_ob).first()

    if request.method == 'POST':
        form = CommunitySelectForm(request.POST, instance=full_user_profile)
        if form.is_valid():

            form.save()
            context = {'user': full_user_profile, 'full_user_profile':full_user_profile}
            context['communities'] = context['user'].community_preferences.all()

            return render(request, 'qa/profile.html', context)
    else:
        form = CommunitySelectForm()
    return render(request, 'qa/select_communities.html', {'form' : form})

Solution

  • You are only passing the instance to the form during POST requests, which means that when the user revisits the page with a GET request, the form isn't bound to any instance and the previous selections don't appear.

    You just need to pass the instance when you initialise the form:

    else:
        form = CommunitySelectForm(instance=full_user_profile)
    return render(request, 'qa/select_communities.html', {'form' : form})