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)))
)
有效,而且它只执行一次查询,而不是每个功能请求一加一或二。
我正在向我的网站添加一个非常简单的路线图投票功能,人们可以在其中添加功能请求,然后人们可以对彼此的建议进行投票。基础非常简单:
# 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)))
)
有效,而且它只执行一次查询,而不是每个功能请求一加一或二。