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

如何在Django中构建模型以追踪用户文章阅读状态?

解决方案:通过中间模型追踪阅读状态

这个需求很常见,核心是得记录用户和文章之间的阅读关联关系——毕竟现有模型里完全没有字段能追踪“谁读了哪篇文章”。咱们可以通过新增一个中间模型来存储阅读记录,具体方案如下:

1. 修改/新增模型

首先加一个ArticleReadRecord模型,用来记录用户阅读文章的时间(用时间比单纯存“已读状态”更灵活,还能知道用户什么时候读的);同时调整Article模型,通过ManyToManyField关联User,并指定用这个中间模型来存储关联数据:

from django.db import models
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager

class UserManager(BaseUserManager):
    # 这里默认你已经实现了create_user、create_superuser等必要方法
    pass

class User(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(unique=True)
    name = models.CharField(max_length=20, blank=True)
    is_staff = models.BooleanField(default=False)
    is_active = models.BooleanField(default=True)
    date_joined = models.DateTimeField(auto_now_add=True)
    objects = UserManager()

# 新增的阅读记录中间模型
class ArticleReadRecord(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='read_records')
    article = models.ForeignKey('Article', on_delete=models.CASCADE, related_name='read_records')
    read_at = models.DateTimeField(auto_now_add=True)  # 有这条记录就代表用户已读

    class Meta:
        unique_together = ('user', 'article')  # 确保一个用户对同一篇文章只会有一条阅读记录

class Article(models.Model):  # 注意类名首字母大写,符合Python命名规范
    title = models.CharField(max_length=255, blank=False)
    content = models.TextField(max_length=1000, blank=False)
    created_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name='created_articles')
    created_at = models.DateTimeField(auto_now_add=True)
    # 新增多对多关联,通过中间模型记录阅读状态
    read_by = models.ManyToManyField(User, through=ArticleReadRecord, related_name='read_articles')

2. 实现需求查询

需求1:获取某个用户的未读文章列表

思路就是:查所有文章,排除掉该用户已经读过的那些。可以用exclude快速过滤:

# 假设当前用户是request.user
current_user = request.user
# 获取未读文章
unread_articles = Article.objects.exclude(read_by=current_user)

如果担心关联字段的空值问题,也可以用更严谨的Q查询写法:

from django.db.models import Q

unread_articles = Article.objects.filter(
    ~Q(read_records__user=current_user)
)

需求2:查询某篇文章的已读/未读用户列表

  • 已读用户列表:直接通过文章的read_by字段获取就行:
target_article = Article.objects.get(id=article_id)
read_users = target_article.read_by.all()
  • 未读用户列表:查所有用户,排除掉已读这篇文章的用户:
unread_users = User.objects.exclude(read_articles=target_article)
# 或者用Q查询写法
unread_users = User.objects.filter(
    ~Q(read_records__article=target_article)
)

补充小提示

  • 当用户完成阅读动作时,你只需要执行target_article.read_by.add(current_user),Django会自动帮你在中间表创建一条阅读记录;
  • unique_together能避免同一个用户重复记录同一篇文章的阅读状态,减少冗余数据;
  • 把原类名article改成Article是遵循Python的大驼峰命名规范,建议保持代码风格统一。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:22:49