Submit form including many-to-many field

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:

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:

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:

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):

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