djangodjango-modelsdjango-querysetmanytomanyfield

.all() on ManyToMany field in Django returns empty QuerySet


I have a model "CustomUserGroup" which has a ManyToMany field with Django's User object passed:

class CustomUserGroup(models.Model):
    custom_group_name = models.CharField(max_length=50,unique=True)
    users= models.ManyToManyField(User)

    class Meta:
        verbose_name_plural = 'Custom Groups'
        ordering = ['custom_group_name']


    def __unicode__(self):
        return self.custom_group_name
    
    def __repr__(self):
        return self.custom_group_name

    def __str__(self):
        return self.custom_group_name

Here is the corresponding form:

...

from ajax_select.fields import AutoCompleteSelectMultipleField

class GroupForm(forms.ModelForm):
    class Meta:
        model = CustomUserGroup
        fields = ['custom_group_name','users',]
        
    users = AutoCompleteSelectMultipleField('users', required=True, help_text=None)

I wanted all users to be able ot create a new CustomUserGroup object:

def index(request):
    groups = CustomUserGroup.objects.all()
    if request.method == 'POST':
        form = GroupForm(request.POST)
        if form.is_valid():
            new_group = form.save(commit=False)
            new_group.save()
            return render(request, 'chat/new_group_created.html', {'group_name': new_group.custom_group_name})
        else:
            return HttpResponse('A group with such name already exists. Please return and change the group name.')
    else:
        form = GroupForm()
    return render(request, 'chat/index.html', {'form': form, 'groups': groups})

My problem is that I think I haven't configured this field correctly, because every time I run the "room" view in my views.py, I get HttpResponse('You shall not pass'), no matter which users have been added to the group before.

def is_member(user,group): # a function to check some of the parameters
    print(user)
    print(group)
    print(group.users.all())
    return user in group.users.all() # and return T/F based on whether the current user is a member 

def room(request, room_name):
    current_user = request.user
    context = {'room_name': room_name}
    if CustomUserGroup.objects.filter(custom_group_name = room_name).exists():
        group = CustomUserGroup.objects.get(custom_group_name=room_name)
        if is_member(current_user,group):
            return render(request, 'chat/room.html', context)
        else:
            return HttpResponse('You shall not pass')
    else:
        return render(request, 'chat/no_such_room.html', context)

print(user) -> works fine
print(group) -> this one too
print(group.users.all()) -> <QuerySet []>

Do you have an idea what could be wrong here?


Python 3.10.4, Django 4.1.6

The problems seems to be connected to the model itself, not the form or its widget, because even in the database there is no "users" column at all


Solution

  • In the documentation for the ModelForm class' save() method, it says that Django doesn't automatically save many-to-many data when you first use form.save(commit=False) and then new_object.save() (as opposed to form.save(commit=True)). And that the solution is to run form.save_m2m() after new_object.save().

    So in your case, either use new_group = form.save(commit=True) or:

    new_group = form.save(commit=False)
    new_group.save()
    form.save_m2m()