# Submit form including many-to-many field

**URL:** <https://forum.djangoproject.com/t/submit-form-including-many-to-many-field/2143>\
**Category:** Using Django\
**Created:** [April 28, 2020, 12:05am UTC](https://forum.djangoproject.com/t/submit-form-including-many-to-many-field/2143 "2020-04-28T00:05:12Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![lincal](https://sea2.discourse-cdn.com/flex026/user_avatar/forum.djangoproject.com/lincal/32/1188_2.png) [@lincal](https://forum.djangoproject.com/u/lincal)\
**Post date:** [April 28, 2020, 12:05am UTC](https://forum.djangoproject.com/t/submit-form-including-many-to-many-field/2143/1 "2020-04-28T00:05:12Z")

</div>

My objective is to implement the same kind of features than in admin panel with a many to many relationship. Everything seem to work all right, but when I submit my form, I get some strange results: I’m probably missing something but I cannot figure out what goes wrong.

For now, when I add lines, everything is OK. Problems occur when I try to remove lines from the group.  
I’m taking about users, I have a first list of ‘all users’ and the second one will make a group.  
When I had a user, then remove another one, the form cannot be validated; the list is empty, the removed user “disappear” (it is not in the group list nor among “all users”.  
If I remove one user, then add a new one, the only user in my form after validation is the one I added, all other ones are removed.

I hope I’m clear, many thanks in advance for your advise.

Here are the related code blocks.

Models:

```python
class UserComp(models.Model):
    """
    Link between users and companies
    Used to restrict display to companie(s) the users belong to
    """
    user = models.OneToOneField(User, on_delete=models.CASCADE, verbose_name="Utilisateur")
    company = models.ForeignKey(Company, on_delete=models.CASCADE, verbose_name="Société")
    phone_regex = RegexValidator(regex=r'^0[0-9]([.-]?[0-9]{2}){4}$', message=("Format de numéro de téléphone invalide"))
    phone_num = models.CharField("numéro de téléphone", validators=[phone_regex], max_length=14, null=True, blank=True)
    is_admin = models.BooleanField("administrateur", default=False)

class EventGroup(models.Model):
    """
    Groups of users
    The link with events is supported by the Event
    (as groups can be reused in several Events)
    """
    company = models.ForeignKey(
        Company, on_delete=models.CASCADE, verbose_name="société"
    )
    users = models.ManyToManyField(UserComp, verbose_name="utilisateurs", blank=True)
    group_name = models.CharField("nom", max_length=100)
    weight = models.IntegerField("poids", default=0)

```

The form:

```python
class GroupDetail(forms.ModelForm):
    users = forms.ModelMultipleChoiceField(
        label="Dans le groupe",
        queryset=None,
        widget=forms.SelectMultiple,
        required=False
        )
    all_users = forms.ModelMultipleChoiceField(
        label="Utilisateurs",
        queryset=None,
        widget=forms.SelectMultiple,
        required=False
        )
    
    class Meta:
        model = EventGroup
        fields = ['group_name', 'weight', 'all_users', 'users']

    def __init__ (self, *args, **kwargs):
        super(). __init__ (*args, **kwargs)
        instance = kwargs.get('instance', None)
        if instance is not None:
            # Users to be selected : all users except the ones already in group
            self.fields['all_users'].queryset= UserComp.objects.\
                                                        filter(company=instance.company).\
                                                        exclude(eventgroup=instance).\
                                                        order_by('user __last_name', 'user__ first_name')
            # Current users in group
            self.fields['users'].queryset = instance.users.all().\
                                                     order_by('user __last_name', 'user__ first_name')

```

The view:

```python
def GroupInfo(request, pk):
    current_group = EventGroup.objects.get(id=pk)
    list_users = [elt.id for elt in current_group.users.all()]
    group_form = GroupDetail(request.POST or None, instance=current_group)

    if request.method == 'POST':
        usr_list = [elt.id for elt in current_group.users.all() if elt not in request.POST.getlist('all_users')]
        usr_list += [int(elt) for elt in request.POST.getlist('users')]
        group_form.fields['users'].queryset = UserComp.objects.filter(id__in=usr_list)

        if group_form.is_valid():
            new_group = group_form.save()
            for usr in usr_list:
                new_group.users.add(usr)
            new_group.save()
        else:
            print(group_form.errors)

    return render(request, "polls/group_info.html", locals())

```

To move a user from one list (actually select multiple HTML object), I have this kind of js code (a function called once or within a loop on double click, move selected items (1 or several ones), or move all items):

```javascript
let new_option = new Option($(this).text(), $(this).val())
$('#id_dest').append(new_option);
$(this).remove();

```

On the front side, I made 2 tests:

1. Select all lines in the “group” part before submitting: I should retrieve the exhaustive list of users in group and build it from this list
2. Select only changes, new users in “group” list, users to remove in “all\_users” list.  
In one way or another, when I remove a user from the group, it is not transmitted and it’s still in the group.

I made many tests, the lists seem ok on submit but the view does not receive the right information.  
Thus, I implemented a workaround: I added an hidden charfield to my form and I manage the list of IDs in this string.  
On POST, I convert it to a list and rebuild the group with the IDs in list  
Everything works fine, but I cannot imagine there is not a way to directly manage lists
