简体   繁体   中英

How can I filter a queryset inside a django form?

I'm trying to add chat functionality to my app and right now I can add users to existing chats but what I need to do is filter users that are not already in the chat in the form. I'm using django form with passed arguments to filter my users but I'm not getting any results. My Chat model has a m2m field to user called ' users ' and my User has a m2m field called ' friends ' with itself.

forms.py

class AddUserToChatForm(forms.ModelForm):

    class Meta:
        model = Chat
        fields = ('users', )

    def __init__(self, chat, friends, request, *args, **kwargs):
        self.request = request
        self.chat = chat
        self.friends = friends
        super(AddUserToChatForm, self).__init__(*args, **kwargs)
        self.fields['users'] = forms.ModelMultipleChoiceField(queryset=self.request.user.friends.exclude(user__in=chat.users.all()),
                                                              widget=forms.CheckboxSelectMultiple
                                                              (attrs={'class': 'add-people-to-chat-form'}),
                                                              label='Friends:')

views.py

def add_users_to_chat(request, pk):
    chat = Chat.objects.get(pk=pk)
    friends = request.user.friends.all()
    if request.method == 'POST':
        form = AddUserToChatForm(chat, friends, request, request.POST)
        if form.is_valid():
            users_to_add = form.cleaned_data['users']
            chat.users.add(*users_to_add)
            chat.save()
            return redirect('messages')
    else:
        form = AddUserToChatForm(chat, friends, request, instance=None)
    return render(request, 'add_users_to_chat.html', {'form': form, 'chat': chat, 'friends': friends})

EDIT

Looks like my exclude statement has no effect because when I switch it to filter the set returns all of the user friends.

UPDATE

I was able to retreive the required users using difference method like this: in view:

chat = Chat.objects.get(pk=pk)
friends = request.user.friends.all()
chat_users = chat.users.all()
queryset = friends.difference(chat_users)

and pass it to the form

def __init__(self, queryset, request, *args, **kwargs):
    self.request = request
    self.queryset = queryset
    super(AddUserToChatForm, self).__init__(*args, **kwargs)
    self.fields['users'] = forms.ModelMultipleChoiceField(queryset=self.queryset,
                                                          widget=forms.CheckboxSelectMultiple
                                                          (attrs={'class': 'add-people-to-chat-form'}),
                                                          label='Friends:')

getting users with difference method but now when I try to submit the form I get this error: Calling QuerySet.filter() after difference() is not supported.

Debugger quits execution on this line in view:

users_to_add = form.cleaned_data['users']

As the fields are automatically generated by the ModelForm, it is best to define only the a queryset in init:

def __init__(self, chat, friends, request, *args, **kwargs):
    self.request = request
    self.chat = chat
    self.friends = friends
    super(AddUserToChatForm, self).__init__(*args, **kwargs)
    self.fields['users'].queryset = self.request.user.friends.exclude(user__in=chat.users.all())

I was able to achieve the wanted result by querying using exclude after all:

in view:

queryset = friends.exclude(id__in=chat_users)

and now everything works as intended

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM