如何在Django模板中检查用户是否订阅了对应产品
解决Django模板中判断用户是否订阅产品的问题
问题根源
你尝试的模板代码无法运行,核心原因是Django模板语法不允许在查询集上直接调用带参数的filter()方法(比如request.user.subscriptions_to_product.filter(model_id=content.model_id)),模板仅支持调用无参数的方法或直接访问属性。
解决方案
下面提供两种高效且符合Django规范的实现方式:
方案1:视图预获取订阅ID集合(简单高效)
在视图中提前查询当前用户已订阅的所有MyModels的ID,存入集合后传入模板,模板直接通过in判断即可,避免模板内触发额外数据库查询。
修改users/views.py:
from django.contrib.auth.decorators import login_required from posts.models import ModelContent, Category, MyModels, Subscription @login_required(login_url='/user/login') def homepage(request): content = ModelContent.objects.all() categorys = Category.objects.all() models = MyModels.objects.all() suggestions = MyModels.objects.all()[:3] # 预获取当前用户已订阅的模型ID集合 subscribed_model_ids = Subscription.objects.filter( user=request.user, is_subscribed=True ).values_list('model__id', flat=True) # 转成集合,提升判断效率 subscribed_model_ids = set(subscribed_model_ids) context = { "categorys": categorys, "models": models, "content": content, "suggestions": suggestions, "subscribed_model_ids": subscribed_model_ids # 新增变量 } return render(request, 'users/home.html', context)
修改模板代码:
<ul> {% for content in content %} {% if content.model.is_premium %} {% if content.model.id in subscribed_model_ids %} <li>User Subscribed</li> {% else %} <li>User Not Subscribed</li> {% endif %} {% else %} <li>Not premium</li> {% endif %} {% endfor %} </ul>
方案2:使用annotate和Exists子查询(数据库层面高效处理)
通过Django ORM的注解功能,在获取ModelContent时直接为每个对象添加user_is_subscribed属性,一次性完成所有判断,彻底避免N+1查询问题。
修改users/views.py:
from django.contrib.auth.decorators import login_required from django.db.models import Exists, OuterRef from posts.models import ModelContent, Category, MyModels, Subscription @login_required(login_url='/user/login') def homepage(request): # 子查询:判断当前用户是否订阅该模型 subscription_subquery = Subscription.objects.filter( user=request.user, model=OuterRef('model'), is_subscribed=True ) # 为ModelContent添加user_is_subscribed注解 content = ModelContent.objects.annotate( user_is_subscribed=Exists(subscription_subquery) ) categorys = Category.objects.all() models = MyModels.objects.all() suggestions = MyModels.objects.all()[:3] context = { "categorys": categorys, "models": models, "content": content, "suggestions": suggestions } return render(request, 'users/home.html', context)
修改模板代码:
<ul> {% for content in content %} {% if content.model.is_premium %} {% if content.user_is_subscribed %} <li>User Subscribed</li> {% else %} <li>User Not Subscribed</li> {% endif %} {% else %} <li>Not premium</li> {% endif %} {% endfor %} </ul>
补充说明
- 两种方案都规避了模板内执行数据库查询的问题,其中方案2通过一次查询完成所有判断,性能最优;
- 建议给
Subscription模型添加唯一约束(比如UniqueConstraint(fields=['user', 'model'], name='unique_user_model_subscription')),避免生成重复的订阅记录。
内容的提问来源于stack exchange,提问作者victor
相关产品推荐
相关产品推荐

