2015-10-31 62 views
0

当我加载我的菜单选项卡时,我有很多重复的查询(在Django的调试工具栏),我确定我可以优化这个,但没有找到好的方法。需要一些意见重复查询

型号:

class Categorie(models.Model): 
    name = models.CharField(max_length=30) 
    visible = models.BooleanField(default = False) 

    def __str__(self): 
     return self.nom 

    def getscateg(self): 
     return self.souscategorie_set.all().filter(visible = True) 


class SousCategorie(models.Model): 
    name = models.CharField(max_length=30) 
    visible = models.BooleanField(default = False) 
    categorie = models.ForeignKey('Categorie') 

    def __str__(self): 
     return self.name 

    def gettheme(self): 
     return self.theme_set.all().filter(visible = True) 


class Theme(models.Model): 
    name = models.CharField(max_length=100) 
    visible = models.BooleanField(default = False) 
    souscategorie = models.ForeignKey('SousCategorie') 

    def __str__(self): 
     return self.name 

浏览:

def page(request): 
    categs = Categorie.objects.filter(visible = True) 

    return render(request, 'page.html', locals()) 

模板:

{% for categ in categs %} 

    <li> 
     {{categ.name}} 
     <ul> 
      {% for scateg in categ.getscateg %} 

       <li> 
        {{scateg.name}} 
        <ul> 

         {% for theme in scateg.gettheme %} 

          <li>{{ theme.name }}</li>  

         {% endfor %}     

        </ul>    
       </li> 

      {% endfor %} 
     </ul> 
    </li> 

{% endfor %} 

我看看prefetch_related但只有当我想从SousCategorie和SousCategorie从主题加载Categorie工作,所以如果我明白我需要与此相反......

回答

0

在Django中,每当您评估一个新的查询集时执行查询,因此您需要减少正在使用的查询集的数量。这里是正在发生的事情:

  • 您创建一个查询集Categorie.objects.filter(visible=True),并传递到视图层,还有第一个查询在此标记{% for categ in categs %}
  • 在循环中执行,你每个类别调用一个方法categ.getscateg返回一个新的查询集return self.souscategorie_set.all().filter(visible = True),这个查询集将在第二循环在你的模板执行{% for scateg in categ.getscateg %}
  • 同样的事情发生与{% for theme in scateg.gettheme %}

使用prefetch_related是明智之举,尝试像(没有测试):

Categorie.objects.filter(visible=True, souscategorie_set__visible=True, souscategorie_set__theme_set__visible=True).prefetch_related('souscategorie_set__theme_set')

prefetch_related作品通过运行第一查询加载满足您的当前过滤器的类别,然后执行第二查询加载所有子类别等。

在其他情况下,你可以使用select_related,但只能在一个单一的查询可以使用,作为一个例子,它会如果你需要一个主题的类别和子类别,如工作:

Theme.objects.filter(pk=1).select_related('souscategorie__categorie')

这里的区别是主题是ForeignKey,所以它只有一个子类别,它可以加载一个单一的联接,这意味着只有当您的查询集来自模型时,您才可以使用select_related点我认为它也适用于OneToOneField

+0

谢谢您的回答,其实你的主张没有为我工作,我出现此错误:无法将关键字'souscategorie_set'解析为字段。我尝试用这种方法找到一种方法。其实在django调试工具栏我有105重复查询105查询,但他们大多数需要0ms执行,所以没有影响在页面加载,我想我应该发布我的真实模板和查询日志揭露我的问题。 – V1ce

+0

我使用了你在问题中给出的信息,如果你得到这个错误的名称是错误的,请在页面上看看[访问相关对象](https://docs.djangoproject.com/en/1.8/REF /模型/关系/)。 105个查询是非常糟糕的,即使它现在以0ms运行,您应该尝试修复它。另外,我建议阅读[关于优化的文档](https://docs.djangoproject.com/en/1.8/topics/db/optimization/) –

0

我必须使用“与” 2减少我查询集

这是一个好点,但我总是有很多重复的(如44式两份51个查询),例如我打我的数据库,当我这样做即:

{% for categ in categs %} 
    {% with currscat=categ.getscateg %} 

     <li class = "{% if currscat %} has_menu {% endif %}"> {{categ.name}} # This line hit database 

      {% if currscat %} # This line hit database 

        <ul class = "menu-1"> ... </ul> 

      {% endif %} 

     </li> 

    {% endwith %} 
{% endfor %} 

我尝试使用prefetch_related这样的:

categs = Categorie.objects.filter(visible=True).prefetch_related('souscategorie_set') 

但是那只是添加查询数据库,不降低...

有些建议吗?

谢谢

2

解决了!

如果它能够帮助:

from .models import Categorie, SousCategorie, Theme, SousTheme 
from django.db.models import Prefetch 

pf_souscategorie = Prefetch('souscategorie_set', SousCategorie.objects.filter(visible=True)) 
pf_theme = Prefetch('souscategorie_set__theme_set', Theme.objects.filter(visible=True)) 
pf_soustheme = Prefetch('souscategorie_set__theme_set__soustheme_set', SousTheme.objects.filter(visible=True)) 

categs = Categorie.objects.filter(visible=True).prefetch_related(pf_souscategorie, pf_theme, pf_soustheme) 

,并在模板调用是这样的:

{% with currscat=categ.souscategorie_set.all %} 
{% with currth=souscateg.theme_set.all %} 
{% with currsth=theme.soustheme_set.all %} 

再见