在Django中高效展示标签筛选后文章的关联标签列表
解决Django多对多关联的N+1查询问题
当前代码里,prefetch_related('publications')只预取了指定标签下的所有文章,但每篇文章关联的tags并没有被预取,所以在模板里遍历publication.tags时,每篇文章都会触发一次单独的数据库查询,也就是典型的N+1问题。
直接用嵌套预取就能解决这个问题,借助Django的Prefetch对象,在预取文章的同时,把每篇文章的标签也一起预取出来:
修改后的views.py代码:
# views.py from .models import Tag, Publication from django.shortcuts import get_object_or_404, render from django.db.models import Prefetch def publications_tagged(request, name): tag = get_object_or_404( Tag.objects.prefetch_related( # 预取当前标签下的文章,同时预取每篇文章的所有关联标签 Prefetch( 'publications', queryset=Publication.objects.prefetch_related('tags') ) ), name=name ) return render(request, 'myapp/tagged_questions.html', {'tag': tag})
效果说明
修改后,Django只会执行3次数据库查询:
- 查询指定名称的Tag
- 查询该Tag关联的所有Publication
- 查询这些Publication对应的所有Tag,并自动关联到对应的文章
模板里可以正常遍历文章和它们的标签,不会触发额外查询:
<!-- tagged_questions.html --> <h1>标签 {{ tag.name }} 下的文章</h1> {% for publication in tag.publications %} <div class="publication-item"> <h3>{{ publication.name }}</h3> <p>{{ publication.text|truncatewords:30 }}</p> <div class="tag-list"> {% for tag in publication.tags %} <span class="tag">{{ tag.name }}</span> {% endfor %} </div> </div> {% endfor %}
这种方式和StackOverflow的标签列表优化思路一致,一次性拉取所有需要的关联数据,避免反复查询数据库,大幅提升页面渲染效率。
内容的提问来源于stack exchange,提问作者whatserface
相关产品推荐
相关产品推荐

