Stuart Cornell
Stuart Cornell

Reputation: 23

Annotated django queryset is getting ignored during serialization

I have a ModelViewSet where I want to annotate the list() response. I've extended the queryset with an annotation and added the field to the serializer, but the serializer just ignores the new data and doesn't add the field at all in the final data.

I am using a customized get_queryset() too (show abbreviated here) which is definitely getting called and producing the right annotations. It just doesn't show up in the REST API response. If I set default=None on the serializer field definition, it appears in the response.

class SequenceSerializer(serializers.ModelSerializer):
    unread=serializers.IntegerField(read_only=True)
    .....

class SequenceViewSet(viewsets.ModelViewSet,ScopedProtectedResourceView):
    authentication_classes = [OAuth2Authentication]
    queryset = Sequence.objects.all()
    serializer_class = SequenceSerializer
    .....

    def get_queryset(self):
        queryset = Sequence.objects.all().filter(<..... some filter>)           
        queryset = queryset.annotate(unread=FilteredRelation('unreadseq',
            condition=Q(unreadseq__userid=self.request.user)))
        print("Seq with unread",queryset.values('id','unread')) ## <<<<this shows the correct data
        return queryset

    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        serializer = self.get_serializer(queryset, many=True)
        return Response(serializer.data) ##<<< this is missing the annotation

I have been banging my head against this all day and I can't for the life of me see what's going wrong. Any ideas please?

-- more info:

class UnreadSeq(models.Model):
    userid = models.ForeignKey('auth.User', on_delete=models.CASCADE)
    seqid = models.ForeignKey(Sequence, on_delete=models.CASCADE)
    class Meta:
        unique_together=('seqid','userid')
        verbose_name = "UnreadSeq"
        verbose_name_plural = "UnreadSeqs"

class Sequence(models.Model):
    userid = models.ForeignKey('auth.User', on_delete=models.SET_NULL,null=True)
    topic = models.ForeignKey('Topic',on_delete=models.CASCADE,null=False,blank=False)
    .....
    class Meta:
        verbose_name = "Sequence"
        verbose_name_plural = "Sequences"

Upvotes: 2

Views: 1328

Answers (1)

mon io
mon io

Reputation: 752

I think that this annotation don't return Integer. Try to annotate (you want to COUNT unreadseq) like this:

def get_queryset(self):
    mytopics=getMyTopics(self.request,False)
    queryset = Sequence.objects.all().filter(<..... some filter>)

    count_unreadseq = Count('unreadseq', filter=Q(unreadseq__userid=self.request.user))
    queryset=queryset.annotate(unread=count_unreadseq)

    ...

EDITED after comments to get unreadseq ids

def get_queryset(self):
    mytopics=getMyTopics(self.request,False)
    queryset = Sequence.objects.all().filter(<..... some filter>)

    unreadseq_ids = UnreadSeq.objects.filter(seqid=OuterRef('pk'), userid=self.request.user).values('pk')

    queryset=queryset.annotate(unread=Subquery(unreadseq_ids))
    ...

Also you need to edit serializer:

class SequenceSerializer(serializers.ModelSerializer):
    unread=serializers.IntegerField(read_only=True)
    .....

Upvotes: 2

Related Questions