R
R
reqww2020-09-04 16:44:04
Django
reqww, 2020-09-04 16:44:04

Annotation problem?

There are the following models:

class Chat(models.Model):
    participants = models.ManyToManyField(Contact, related_name='chats')
    messages = models.ManyToManyField(Message, blank=True)

    def __str__(self):
        return f'{self.pk}'

    class Meta:
        verbose_name = 'Чат'
        verbose_name_plural = 'Чаты'

This is a chat model, with a defined reverse name for chat participants
. There is a contact model:

class Contact(AbstractBaseUser, PermissionsMixin):
    '''Кастомная модель пользователя'''
    email = models.EmailField(verbose_name='email', max_length = 60, unique = True)
    slug = models.SlugField(default='')
    first_name = models.CharField(max_length=30, default = '')
    last_name = models.CharField(max_length=30, default = '')
    phone_number = models.CharField(max_length=11)
    date_joined = models.DateTimeField(verbose_name='date joined', auto_now_add = True)
    last_login = models.DateTimeField(verbose_name='last login', auto_now = True)
    is_admin = models.BooleanField(default=False)
    is_staff = models.BooleanField(default=False)
    is_superuser = models.BooleanField(default=False)
    avatar = models.ImageField(upload_to='user_avatars/%Y/%m/%d', blank=True)
    is_active = models.BooleanField(default=False)
    status = models.CharField(max_length=100, default='', blank=True)
    friends = models.ManyToManyField('self', blank=True)
    

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['first_name', 'last_name', 'phone_number', 'slug']

    objects = ContactManager()

    def __str__(self):
        return self.email

    def get_url(self):
        try:
            return self.avatar.url
        except ValueError:
            return None

    class Meta:
        verbose_name = 'Контакт'
        verbose_name_plural = 'Контакты'
        ordering = ['-date_joined']

The manager is also written:
class ContactManager(BaseUserManager):
    '''Мэнэджер кастомного пользователя'''
    def create_user(
        self,
        email,
        first_name,
        last_name, 
        phone_number, 
        slug, 
        password = None
    ):
        user = self.model(
            email=self.normalize_email(email),
            first_name=first_name.capitalize(),
            last_name=last_name.capitalize(),
            phone_number=phone_number,
            slug=slug
        )

        user.set_password(password)
        user.save(using = self._db)

        return user

    def create_superuser(
        self, 
        email, 
        first_name, 
        last_name, 
        phone_number, 
        slug, 
        password = None
    ):
        user = self.model(
            email=self.normalize_email(email),
            first_name=first_name,
            last_name=last_name,
            phone_number=phone_number,
            slug=slug
        )

        user.set_password(password)

        user.is_admin = True
        user.is_staff = True
        user.is_superuser = True
        user.is_active = True

        user.save(using = self._db)

        return user

There is a view to display a specific contact:

class ContactCustomViewSet(RetrieveUpdateDestroyPermissionViewset):
    '''Обзор, обновление и удаление контакта'''
    serializer_class = ContactDetailSerializer
    permission_classes = [permissions.IsAuthenticated, IsCurrentUser, ]
    permission_classes_by_action = {
        'retrieve': [permissions.IsAuthenticated, ]
    }

    def get_queryset(self):
        pk = self.kwargs['pk']
        contact = get_object_or_404(Contact, id=pk)
        queryset = Contact.objects.filter(id=pk).annotate(
            is_friend=Count('friends', filter=Q(friends=self.request.user))
        ).annotate(
            num_friends=Count('friends')
        ).annotate(
            current_user=Count('slug', filter=Q(slug=self.request.user.slug))
        ).annotate(
            is_sent=Exists(
                AddRequest.objects.filter(
                    sender=self.request.user,
                    receiver=contact,
                )
            )
        ).annotate(
            is_sent_to_you=Exists(
                AddRequest.objects.filter(
                    sender=contact,
                    receiver=self.request.user
                )
            )
        ).annotate(
            chat_id=Sum('chats__id', filter=Q(chats__participants=self.request.user))
        )
        return queryset



5f524389938a3965537335.png

In the last annotation , I'm trying to display the id of the current user's chat with the user whose page he went to, but an unexpected problem arises. id 30 does not exist at all

Further, if I bring the view to the following form:
class ContactCustomViewSet(RetrieveUpdateDestroyPermissionViewset):
    '''Обзор, обновление и удаление контакта'''
    serializer_class = ContactDetailSerializer
    permission_classes = [permissions.IsAuthenticated, IsCurrentUser, ]
    permission_classes_by_action = {
        'retrieve': [permissions.IsAuthenticated, ]
    }

    def get_queryset(self):
        pk = self.kwargs['pk']
        contact = get_object_or_404(Contact, id=pk)
        queryset = Contact.objects.filter(id=pk).annotate(
            is_friend=Count('friends', filter=Q(friends=self.request.user))
        ).annotate(
            num_friends=Count('friends')
        ).annotate(
            current_user=Count('slug', filter=Q(slug=self.request.user.slug))
        ).annotate(
            is_sent=Exists(
                AddRequest.objects.filter(
                    sender=self.request.user,
                    receiver=contact,
                )
            )
        ).annotate(
            is_sent_to_you=Exists(
                AddRequest.objects.filter(
                    sender=contact,
                    receiver=self.request.user
                )
            )
        )
        # .annotate(
        #     chat_id=Sum('chats__id', filter=Q(chats__participants=self.request.user))
        # )
        return queryset


The result is the following:

5f5243950e7df690887366.png

Friends stop being naughty, which is logical, but I don’t understand one thing. Why does the last annotation affect any other at all, and also: how to correctly build a query to the database to get the desired result, namely: how to display the chat ID with the user whose page I go to. My front is pulling the chat id from the response to then refer to the correct address with the correct chat id to make the connection to the correct chat accordingly

I would really appreciate any help

Answer the question

In order to leave comments, you need to log in

1 answer(s)
S
Sergey Tikhonov, 2020-09-06
@reqww

  • In vain you summarize identifiers in the annotation
  • Chat for two interlocutors must be received separately
    Chat.objects.filter(participants=request.user).filter(participants__id=friend_id_from_url)

  • In addition, in such a data scheme, several chats are possible in which both participants (and maybe someone else) participate. And a message can belong to several chats at once

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question