Django / DRF:使用额外(计算)信息注释模型

Django / DRF: annotate a model with extra (computed) information

我正在向我的网站添加一个非常简单的路线图投票功能,人们可以在其中添加功能请求,然后人们可以对彼此的建议进行投票。基础非常简单:

# models.py
class FeatureRequest(models.Model):
    title = models.CharField(max_length=50)
    description = models.TextField()
    author = models.ForeignKey(User, editable=False, on_delete=models.CASCADE)
    is_implemented = models.BooleanField(default=False, editable=False, db_index=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)


class Vote(models.Model):
    feature = models.ForeignKey(FeatureRequest, editable=False, on_delete=models.CASCADE)
    user = models.ForeignKey(User, editable=False, on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        unique_together = ["feature", "user"]

#views.py
class RoadmapController(viewsets.ModelViewSet):
    permission_classes = (AuthorOrReadOnlyPermission,)
    serializer_class = FeatureRequestSerializer

    def get_queryset(self):
        return FeatureRequest.objects.filter(is_implemented=False)

    def perform_create(self, serializer):
        return serializer.save(author=self.request.user)

# serializers.py
class FeatureRequestSerializer(serializers.ModelSerializer):
    class Meta:
        model = FeatureRequest
        fields = "__all__"

还有一个单独的视图用于实际创建和删除选票,但我的问题在这里不需要。

我想要的是功能请求列表的响应包括每一个的投票数,以及一个布尔值,如果登录用户已经投票:

[
  {
    "title": "This is a feature request", 
    "description": "Foo bar", 
    "author": 1, 
    "number_of_votes": 1, 
    "has_my_vote": true
  }
]

我已经想通了,我可以将我的查询集更改为FeatureRequest.objects.filter(is_implemented=False).annotate(number_of_votes=Count("vote")),将number_of_votes = serializers.ReadOnlyField()添加到序列化程序中,并且可以看到投票数。那是最好的方法吗?它为我假设的每个功能请求添加了一个查询。

但最重要的是,我不知道如何将“has_my_vote”布尔值添加到结果中(当然也不知道如何保持这种性能)。

经过反复试验,我想到了这个:

    def get_queryset(self):
        return (
            FeatureRequest.objects.filter(is_implemented=False)
            .annotate(number_of_votes=Count("vote"))
            .annotate(has_my_vote=Exists(Vote.objects.filter(feature=OuterRef("pk"), user=self.request.user)))
        )

有效,而且它只执行一次查询,而不是每个功能请求一加一或二。