2015-10-31 2 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 из темы , поэтому, если я понимаю, мне нужно обратное ...

ответ

0

В Django каждый раз, когда вы оцениваете новый запрос, выполняется запрос, поэтому вам нужно уменьшить количество используемых запросов. Вот что происходит:

  • Вы создаете QuerySet Categorie.objects.filter(visible=True) и передается в слой представления, там первый запрос выполняется на этой метке {% for categ in categs %}
  • Внутри цикла для каждой категории вы находитесь вызов метода categ.getscateg который возвращает новый QuerySet return self.souscategorie_set.all().filter(visible = True), это QuerySet будет выполняться во втором цикле в шаблоне {% 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-debug-toolbar я получил 97 дубликатов для 105 запросов, но большинство из них берут 0 мс для выполнения, поэтому никакого влияния на загрузку страницы, я думаю, что я должен опубликовать свой реальный шаблон и журнал запросов, чтобы разоблачить мою проблему. – V1ce

+0

Я использовал информацию, которую вы указали в своем вопросе, если вы получили эту ошибку, имя неверно, посмотрите на странице о [связанных объектах] (https://docs.djangoproject.com/en/1.8/реф/модели/отношения /). 105 запросов действительно плохо, даже если он работает с 0ms сейчас, вы должны попытаться его исправить. Кроме того, я рекомендую прочитать [документы об оптимизации] (https://docs.djangoproject.com/en/1.8/topics/db/optimization/) –

0

меня сократить свои querysets на 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') 

но вот только добавить запрос к базе данных, не уменьшают ...

Некоторые советы?

Thanks

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 %} 

Bye

Смежные вопросы