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
相关产品推荐
相关产品推荐

