You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何设计最优的点赞功能Django模型,满足登录用户点赞帖子需求

方案对比与最优选择

你写的两个方案本质上底层逻辑是一致的:Django 中的 ManyToManyField 默认会自动生成一个和方案二结构相同的中间关联表,用来存储帖子和用户的点赞对应关系,二者的差异仅在于是否支持自定义扩展。

两个方案的适用场景

  • 方案一:仅需要基础点赞功能时的最优选择
    如果你只需要实现点赞、取消点赞、判断用户是否点赞、查询点赞总数这些基础需求,直接用方案一即可,Django 已经封装好了所有常用操作,代码量最少,维护成本最低:

    # 点赞
    post.likes.add(request.user)
    # 取消点赞
    post.likes.remove(request.user)
    # 判断当前用户是否已点赞
    is_liked = post.likes.filter(id=request.user.id).exists()
    # 获取点赞总数
    like_num = post.likes.count()
    

    完全可以满足你提到的「已登录用户点赞、计数加1」的需求。

  • 方案二:需要扩展点赞属性时的选择
    如果你后续需要存储点赞相关的额外信息,比如点赞时间、点赞用户IP、是否为匿名点赞、软删除标记等,就必须用显式创建中间表的方案二。你也可以把两种方案结合,用 through 参数关联自定义中间表,既保留 Django 多对多字段的封装能力,又支持自定义扩展:

    from django.db import models
    from django.conf import settings
    
    class Post(models.Model):
        title = models.CharField(max_length=255)
        # 通过through参数指定自定义中间表
        likes = models.ManyToManyField(settings.AUTH_USER_MODEL, through="Like")
        # 高并发场景建议加冗余计数字段,避免每次count查询关联表
        like_count = models.PositiveIntegerField(default=0)
    
    class Like(models.Model):
        post = models.ForeignKey(Post, on_delete=models.CASCADE)
        user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
        # 自定义扩展字段:点赞时间
        created_at = models.DateTimeField(auto_now_add=True)
        
        class Meta:
            # 必须加联合唯一约束,避免同一个用户对同一个帖子重复点赞
            constraints = [
                models.UniqueConstraint(fields=['post', 'user'], name='unique_post_user_like')
            ]
    

高并发场景优化方案

如果你的站点访问量较高,每次查询点赞数都调用 count() 遍历关联表会带来较大的性能开销,建议给 Post 模型加 冗余点赞计数字段,也就是上面代码里的 like_count,通过 Django 信号或者重写 save/delete 方法同步更新计数值:

  • 新增点赞记录时,post.like_count += 1 并保存
  • 删除点赞记录时,post.like_count -= 1 并保存
    查询点赞数时直接读取该字段即可,性能提升非常明显。

内容的提问来源于stack exchange,提问作者D_P

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 16:27:03