Search code examples
pythondjangodjango-querysetdjango-orm

Exclude user from an annotation query


I'm trying to query the users presents in a certain conversation. I finally got it working with this annotation:

    products = products.annotate(
        conversation_users=Subquery(
            Conversation.objects.filter(
                product=OuterRef('pk')
            ).annotate(
                users_array=ArrayAgg('users__username')
            ).values_list('users_array', flat=True)[:1]
        )
    )

This is returning a list with the user present in the conversation (in most cases only two). I need to exclude from there the request.user so I get always the value of the user who I am having the conversation with.

I tried using this Q query trying to exclude the request.user:

.filter(~Q(users=user)).values_list('users_array', flat=True)[:1]
        )

but it is making the field now return None. How can I accomplish that?

Edit 1:

Those are the relevant models, Product model:

class Product(models.Model):
    creator = models.ForeignKey(
        User, on_delete=models.CASCADE, related_name='anken')
    content = models.TextField(blank=True, null=True)
    date = models.DateTimeField(auto_now_add=True)
    active = models.BooleanField(default=True)
    intouch = models.ManyToManyField(
        User, related_name='product_intouch', blank=True)

And this is the Conversation model:

class Conversation(models.Model):
    product = models.ForeignKey(
        Product, on_delete=models.CASCADE, related_name='conversations')
    users = models.ManyToManyField(User, related_name='conversations')
    

    def validate_unique(self, *args, **kwargs):
        super().validate_unique(*args, **kwargs)
        if Conversation.objects.filter(product=self.product, users__in=self.users.all()).exists():
            raise ValidationError(
                'A conversation with the same Product and user already exists.')

Solution

  • You filter this out in the aggregate:

    from django.contrib.postgres.aggregates import ArrayAgg
    from django.db.models import OuterRef, Q, Subquery
    
    products = products.annotate(
        conversation_users=Subquery(
            Conversation.objects.filter(
                product=OuterRef('pk'),
            )
            .annotate(users_array=ArrayAgg('users__username', filter=~Q(users=user)))
            .values_list('users_array', flat=True)[:1]
        )
    )