我有一个简单的社交媒体应用程序,与用户,帖子,投票后模型.

class Post(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
    
    ...

    @property
    def score(self):
        total = 0
        for vote in PostVote.objects.all():
            if vote.post == self:
                total += vote.vote
        return total
   
    def get_num_upvotes(self):
        return PostVote.objects.filter(post=self, vote=1).count()

    def get_num_downvotes(self):
        return PostVote.objects.filter(post=self, vote=-1).count()


class PostVote(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
    post = models.ForeignKey(Post, on_delete=models.SET_NULL, null=True)
    vote = models.IntegerField()

在我的views.py中,我试图计算出排名靠前的帖子,并按分数排序.以下是视图代码.

class ListCreatePostAPIView(ListCreateAPIView):
    serializer_class = PostSerializer
    permission_classes = (IsGoodUser | IsAdminUser,)

    def get_queryset(self):
        try:
            queryset = Post.objects.all().exclude(user=None)
            queryset = list(queryset)
            queryset.sort(key=operator.attrgetter("score"), reverse=True)
            return queryset
        except:
            return Post.objects.none()

在序列化程序中,我还会再次重新计算并返回分数,因为我希望将它传递给我的前端.

class PostSerializer(serializers.ModelSerializer):
    score = serializers.SerializerMethodField()
    num_upvotes = serializers.SerializerMethodField()
    num_downvotes = serializers.SerializerMethodField()

    def get_score(self, obj):
        return obj.get_score()

    def get_num_upvotes(self, obj):
        return obj.get_num_upvotes()

    def get_num_downvotes(self, obj):
        return obj.get_num_downvotes()

    class Meta:
        model = Post
        fields = (
            "score",
            "num_upvotes",
            "num_downvotes",
        )

我知道我重新计算分数的次数太多了,因为返回50个虚假帖子/1250个虚假帖子需要3-4秒,但我如何才能真正提高效率呢?我try 过PREFETCH_Related,但我想不出如果对属性进行排序该如何使用它.我真的迷路了,如果有任何帮助,我将不胜感激.

推荐答案

使用Django聚合,而不是手动遍历所有对象的Python 选项,您可能会发现一些立竿见影的改进.这就是您的得分函数将变成的:

@property
def score(self):
    return self.postvote_set.aggregate(Sum('vote')).get('vote__sum')

您可以通过缓存结果或将其存储在模型上来进一步改进这一点.

Edit-将Count更改为Sum

Django相关问答推荐

Django迁移嵌套模型时出错,不带迁移基本模型

在/Contact-Agent/Get()返回的多个对象返回了多个属性--它返回了2

使用自定义模型注册后,Django无法登录

如何在uwsgi中创建单个日志(log)文件?

使用 Pytest 在 Django 中编写测试用例时如何加载特定目录中的所有固定装置

如何在Django中制作一个不 Select 以前日期的日期 Select 器

在 django/python 上访问请求标头

为什么 django 1.7 会为字段 Select 的变化创建迁移?

将现有 auth.User 数据迁移到新的 Django 1.5 自定义用户模型?

Django App 配置不当 - 应用程序模块有多个文件系统位置

Django:使用render或render_to_response时添加响应头

带有消息判断的 Django/Python assertRaises

Django JavaScript 文件

PyCharm 无法正确识别需求 - Python、Django

Django ALLOWED_HOSTS IP 范围

在 docker 容器中创建 django 超级用户而不输入密码

Django 和 VirtualEnv 开发/部署最佳实践

如何使 Django 的开发服务器公开?

ModelForm 上的 Django 和字段集

如何将本地文件分配给 Django 中的 FileField?