E
E
Egegey2021-07-03 13:44:41
Django
Egegey, 2021-07-03 13:44:41

How to properly filter Django Queryset and apply annotate?

I want to filter chats with the participation of the user who requests these chats and count the number of participants for each chat

class Chat(models.Model):
    users = models.ManyToManyField(User, related_name='chats')


def get_queryset(self):
    return Chat.objects.annotate(user_count=Count('users')).filter(users__id=self.request.user.id)


def get_queryset(self):
    return Chat.objects.filter(users__id=self.request.user.id).annotate(user_count=Count('users'))


The first method returns such data. They are correct and I need them:
{
        "id": 146,
        "user_count": 2
    },
    {
        "id": 109,
        "user_count": 3
    },
    {
        "id": 22,
        "user_count": 11
    }


The second returns this:
{
        "id": 146,
        "user_count": 1
    },
    {
        "id": 109,
        "user_count": 1
    },
    {
        "id": 22,
        "user_count": 1
    }


As I understand it, the second method is better, since I first check for the presence of a user in "users", collect such chats and then count the participants as it.
In the first case, I first count the participants for all chats (although I don’t need all chats), and then filter by the presence of a user.

Can you tell me why the second method counts incorrectly?
Is there any difference in speed between these two methods?

Answer the question

In order to leave comments, you need to log in

1 answer(s)
A
Antonio Solo, 2021-07-03
@Egegey

an error in the second because at first you cut off all other users (except one) with a filter and count the number of users for it, the
difference in speed will be if the number of participants is large.
try like this:

def get_queryset(self):
    qs = Chat.objects.filter(users__id=self.request.user.id).values_list('id')
    return Chat.objects.filter(id__in=qs).annotate(user_count=Count('users'))

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question