Django模板中IF嵌套For循环无法正确展示对应分类文章
问题描述
在分类栏目中通过内嵌For循环的IF条件,尝试实现仅展示对应分类下文章的效果,但当前页面会渲染所有已发布文章,无法过滤出仅归属目标分类的内容。
相关代码与截图
- home.html 页面截图:

- 原有home.html代码:
{% if articles.category == Sports %} {% for article in articles %} <div class="position-relative"> <img class="img-fluid w-100" src="{{article.cover.url}}" style="object-fit: cover;"> <div class="overlay position-relative bg-light"> <div class="mb-2" style="font-size: 13px;"> <a href="">{{article.title}}</a> <span class="px-1">/</span> <span>{{article.created_at}}</span> </div> <a class="h4 m-0" href="">{{article.description}}</a> </div> </div> {% endfor %} {% endif %}
- 原有views.py代码:
def home (request): cats = Category.objects.all() articles = Article.objects.filter( is_published=True).order_by('-category') return render (request,'pages/home.html', context={ 'cats': cats, 'articles': articles })
问题根源
现有代码存在两个核心错误,导致过滤逻辑完全失效:
- 判断位置错误:
{% if %}写在了{% for %}循环外层,articles是所有文章的查询集对象,本身不存在单篇文章才有的category属性,外层判断根本不会按预期生效 - 判断语法错误:
Sports没有加引号,Django模板会将其识别为未定义变量而非字符串;就算判断位置正确,直接拿整个文章查询集做分类匹配,也不会对单篇文章生效
修复方案
方案1:后端预处理分组(推荐,性能更优)
先在后端把文章按分类归类,减少模板层的重复判断,适合文章量大的场景。
- 修改views.py:
def home(request): cats = Category.objects.all() published_articles = Article.objects.filter(is_published=True) # 按分类组装对应文章列表 category_articles = {} for cat in cats: category_articles[cat.name] = published_articles.filter(category=cat) return render(request, 'pages/home.html', context={ 'cats': cats, 'category_articles': category_articles })
- 新增字典取值自定义模板过滤器(Django模板默认不支持直接用变量取字典键):
在对应app下新建templatetags文件夹,创建dict_filter.py文件:
from django import template register = template.Library() @register.filter def get_item(dictionary, key): return dictionary.get(key)
- 修改home.html:
{% load dict_filter %} {% for cat in cats %} {# 以体育分类为例,其他分类替换对应判断值即可 #} {% if cat.name == "Sports" %} <section> <h3>{{ cat.name }}</h3> {% for article in category_articles|get_item:cat.name %} <div class="position-relative"> <img class="img-fluid w-100" src="{{article.cover.url}}" style="object-fit: cover;"> <div class="overlay position-relative bg-light"> <div class="mb-2" style="font-size: 13px;"> <a href="">{{article.title}}</a> <span class="px-1">/</span> <span>{{article.created_at}}</span> </div> <a class="h4 m-0" href="">{{article.description}}</a> </div> </div> {% endfor %} </section> {% endif %} {% endfor %}
方案2:模板层直接判断(无需新增过滤器,适合小数据量场景)
不用修改原有views.py,直接调整模板判断逻辑位置,在循环内逐篇校验文章分类即可:
<section> <h3>体育分类</h3> {% for article in articles %} {# 注意字符串值必须加引号,外键关联要取分类的name字段匹配 #} {% if article.category.name == "Sports" %} <div class="position-relative"> <img class="img-fluid w-100" src="{{article.cover.url}}" style="object-fit: cover;"> <div class="overlay position-relative bg-light"> <div class="mb-2" style="font-size: 13px;"> <a href="">{{article.title}}</a> <span class="px-1">/</span> <span>{{article.created_at}}</span> </div> <a class="h4 m-0" href="">{{article.description}}</a> </div> </div> {% endif %} {% endfor %} </section>
注意事项
- 字符串匹配必须加引号:模板中做字符串相等判断时,匹配值必须加双引号,否则会被识别为变量导致判断失效
- 判断位置不能放错:分类判断必须放在文章循环内部,逐篇校验单篇文章的分类属性,不能在循环外层对整个文章查询集做判断
- 外键匹配要取具体字段:如果分类是外键关联,必须取分类的具体字段(比如
category.name)做匹配,不能直接拿外键对象和字符串对比
内容的提问来源于stack exchange,提问作者CARLOS EDUARDO VIEIRA MARTINS
相关产品推荐
相关产品推荐

