Django多对多反向查询:如何判断用户是否将院校加入心愿单
Django多对多关系反向存在性校验实现方案
问题根因
你当前的判断逻辑{% if data.student_set.all %}存在两个核心问题:
- 校验维度错误:该逻辑是判断对应院校是否被任意学生加入过心愿单,未匹配当前登录用户的维度
- 逻辑不合理:对QuerySet直接做if判断仅能校验是否存在数据,无法过滤指定用户的关联关系
实现步骤
前提约定
默认你的Student模型与Django内置User模型是一对一关联,即Student中存在字段user = models.OneToOneField(User, on_delete=models.CASCADE);如果你使用Student作为自定义用户模型,可直接替换下文的request.user.student为request.user。
方案1:视图层预查询(推荐,无N+1性能问题)
先在视图层一次性拉取当前用户的所有收藏院校ID,模板循环时直接做集合存在性校验,性能最优:
- 修改
index视图代码:
def index(request): # 原变量名拼写错误,修正为复数universities universities = University.objects.filter(is_approved=True) user_wish_ids = set() # 用户登录才查询收藏数据 if request.user.is_authenticated: user_wish_ids = set( request.user.student.wishlist.values_list('id', flat=True) ) context = { 'universities': universities, 'user_wish_ids': user_wish_ids } return render(request, 'search/index.html', context)
- 调整模板判断逻辑:
{% for university in universities %} <!-- 院校其他展示代码 --> {% if university.id in user_wish_ids %} <button><em class="icon ni ni-heart-fill" ></em></button> {% else %} <button><em class="icon ni ni-heart"></em></button> {% endif %} {% endfor %}
方案2:模板直接校验(适合数据量小的场景)
如果不想修改视图,也可以直接在模板中调用多对多字段的contains方法校验,但注意该方案会在每次循环时发起数据库查询,院校数量多的话会产生N+1性能问题:
{% for university in universities %} <!-- 院校其他展示代码 --> {% if request.user.student.wishlist.contains university %} <button><em class="icon ni ni-heart-fill" ></em></button> {% else %} <button><em class="icon ni ni-heart"></em></button> {% endif %} {% endfor %}
反向查询的正确写法
如果你一定要用反向关联student_set实现,写法如下,同样存在N+1性能问题:
{% if university.student_set.filter(id=request.user.student.id).exists %} <!-- 实心红心逻辑 --> {% else %} <!-- 空心心逻辑 --> {% endif %}
内容的提问来源于stack exchange,提问作者sixovov947
相关产品推荐
相关产品推荐

