You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django视图自定义导航生成函数运行缓慢,求优化方案

Django导航生成函数性能优化方案

你的代码慢的核心原因是N+1数据库查询问题——循环里每处理一个分类、子分类都要发起新的数据库请求,15个分类+46个子分类下来,额外触发了几十次查询,这是耗时的主要来源。下面是针对性的优化方案:

1. 用预加载减少数据库查询次数

Django提供了select_related(用于一对一/多对一关联)和prefetch_related(用于一对多/多对多关联),可以一次性把所有需要的关联数据查询出来,避免循环中的重复请求。

修改数据查询部分,直接预加载子分类和关联文章:

from django.db.models import Prefetch

def generate_navigation_list(request):
    # 预加载所有关联数据,指定文章按order排序,只查询需要的字段
    article_categories = ArticleCategory.objects.prefetch_related(
        Prefetch(
            'articlesubcategory_set',
            queryset=ArticleSubCategory.objects.prefetch_related(
                Prefetch(
                    'article_set',
                    queryset=Article.objects.order_by('order').only('title', 'slug')
                )
            )
        )
    )
    
    navigation_list = []
    for category in article_categories:
        category_dict = {
            'id': category.id,
            'title': category.name,
            'subcategory': []
        }
        
        # 直接用预加载的子分类,不再发起新查询
        for subcategory in category.articlesubcategory_set.all():
            subcategory_dict = {
                'id': subcategory.id,
                'title': subcategory.name,
                'articles': []
            }
            
            # 用预加载的文章,无需再次filter
            articles = subcategory.article_set.all()
            if articles:
                for article in articles:
                    article_dict = {
                        'title': article.title,
                        'slug': article.slug
                    }
                    subcategory_dict['articles'].append(article_dict)
                category_dict['subcategory'].append(subcategory_dict)
        
        if category_dict['subcategory']:
            navigation_list.append(category_dict)
    
    request.session['navigation_list'] = navigation_list
    request.session.save()

这里用only('title', 'slug')指定只查询需要的字段,避免加载Article模型的冗余数据,进一步提升效率。

2. 缓存导航数据(可选但效果显著)

如果导航内容不是实时更新的,可以把生成好的navigation_list缓存到全局缓存中,不用每次请求都重新生成。比如用Django的缓存框架:

from django.core.cache import cache

def generate_navigation_list(request):
    # 先尝试从缓存获取
    navigation_list = cache.get('site_navigation')
    
    if not navigation_list:
        # 执行上面的预加载查询和导航生成逻辑...
        # 生成后存入缓存,设置过期时间(比如1小时)
        cache.set('site_navigation', navigation_list, 3600)
    
    request.session['navigation_list'] = navigation_list
    request.session.save()

这样只有第一次请求或者缓存过期时才会执行数据查询和生成逻辑,后续请求直接从缓存读取,耗时会降到毫秒级。

3. 去掉不必要的重复查询

原代码中filtered_articles.exists()会触发一次数据库查询,之后循环filtered_articles又会触发一次。预加载后直接用if articles:判断即可,不会额外发起查询。

内容的提问来源于stack exchange,提问作者Nello

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 14:40:10