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

Django中如何基于用户订阅状态分发普通与付费博客内容

实现方案

第一步:优化模型,新增订阅状态判断方法

首先给User模型新增可复用的有效订阅判断方法,同时校验订阅的有效期,避免出现标记为活跃但实际已过期的订阅仍然生效的问题。

# models.py 顶部新增导入
from django.utils import timezone

class User(AbstractBaseUser, PermissionsMixin):
    # 原有字段代码保持不变

    # 新增有效订阅判断方法
    def has_active_subscription(self):
        # 同时校验活跃状态、到期时间两个条件
        return SubscriptionHistory.objects.filter(
            user=self,
            active=True,
            expiry_date__gte=timezone.now()
        ).exists()

注意:你现有SubscriptionHistory模型里的expiry_date设置了auto_now=True,这个配置会导致每次更新订阅记录时自动修改到期时间,不符合业务逻辑,建议改成普通DateTimeField,支付成功时根据用户购买的套餐时长手动计算设置到期时间。

第二步:改造博客列表视图的过滤逻辑

根据用户的登录状态和订阅权限,返回对应可见的博客内容:

def blog(request):
    template_name = 'cms/blog.html'
    user = request.user
    # 先判断用户是否属于付费订阅用户
    is_premium_user = user.is_authenticated and user.has_active_subscription()

    # 基础查询集:未订阅用户默认只能看到非付费内容
    base_blog_query = Blog.objects.all()
    if not is_premium_user:
        base_blog_query = base_blog_query.filter(premium=False)
    
    # 所有分类博客都从已经过权限过滤的基础查询集中提取
    blogs = base_blog_query
    featured_story = base_blog_query.filter(featured_stories=True)
    latest_new = base_blog_query.filter(latest_news=True)
    latest_article = base_blog_query.filter(latest_articles=True)
    premium_blogs = Blog.objects.filter(premium=True) if is_premium_user else None

    context = {
        'blogs':blogs,
        'featured_story':featured_story,
        'latest_new':latest_new,
        'latest_article':latest_article,
        "premium_blog":premium_blogs,
        "is_premium_user": is_premium_user # 可传给模板,用来展示订阅入口、付费内容提示等
    }
    return render(request, template_name, context)

第三步:新增博客详情页权限控制

避免未订阅用户直接通过URL访问付费博客内容:

from django.core.exceptions import PermissionDenied

def blog_detail(request, pk):
    blog = get_object_or_404(Blog, pk=pk)
    user = request.user
    # 付费内容校验订阅权限
    if blog.premium and not (user.is_authenticated and user.has_active_subscription()):
        # 也可以替换为重定向到订阅页面:return redirect('你的订阅页面路由名')
        raise PermissionDenied("该内容为付费专属内容,请先订阅套餐后访问")
    context = {"blog": blog}
    return render(request, 'cms/blog_detail.html', context)

可选优化点

  • 可以把订阅权限判断封装成装饰器,给所有需要付费权限的视图复用
  • 可使用Django缓存机制缓存用户的订阅状态,降低重复查询数据库的压力
  • 新增定时任务,定期将已过期的订阅记录的active字段更新为False,保证数据一致性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 18:45:04