Кэширование наборов запросов и переоценка - PullRequest
1 голос
/ 28 августа 2009

Я собираюсь опубликовать некоторый неполный код, чтобы сделать пример простым. Я запускаю рекурсивную функцию для вычисления некоторых метрик в иерархической структуре.

Категория класса (модели. Модель):

parent = models.ForeignKey('self', null=True, blank=True, related_name='children', default=1)

def compute_metrics(self, shop_object, metric_queryset=None, rating_queryset=None)
    if(metric_queryset == None):
        metric_queryset = Metric.objects.all()
    if(rating_queryset == None):
        rating_queryset = Rating.objects.filter(shop_object=shop_object)

    for child in self.children.all():
        do stuff
        child_score = child.compute_metrics(shop_object, metric_queryset, rating_queryset)

    metrics_in_cat = metric_queryset.filter(category=self) 
    for metric in metrics_in_cat
          do stuff

Надеюсь, этого достаточно, чтобы увидеть, что происходит. Что мне нужно, так это рекурсивная функция, которая будет запускать эти запросы только один раз, а затем передавать результаты. Это, кажется, не происходит прямо сейчас, и это убивает производительность. Если бы это был PHP / MySQL (насколько мне они не нравятся после работы с Django!), Я мог бы просто выполнить запросы один раз и передать их.

Из того, что я понимаю о наборах запросов Django, они не будут оцениваться в моем случае, если набор запросов == Нет, тогда набор запросов = часть материала. Как я могу заставить это? Будет ли он переоценен, когда я сделаю что-то вроде metric_queryset.filter(category=self)?

Меня не волнует свежесть данных. Я просто хочу прочитать из БД один раз для каждой метрики и рейтинга, а затем отфильтровать их позже, не обращаясь к БД снова. Это неприятная проблема, которая, похоже, должна иметь очень простой ответ. Похоже, что травление может работать, но это не очень хорошо объяснено в документации Django.

1 Ответ

3 голосов
/ 28 августа 2009

Я думаю, что проблема в том, что вы не оцениваете набор запросов до тех пор, пока не закончится ваш рекурсивный вызов. Если вы используете list() для принудительной оценки набора запросов, он должен попадать в базу данных только один раз. Обратите внимание, что вам придется изменить строку metrics_in_cat на фильтр уровня Python, а не использовать фильтры наборов запросов.

parent = models.ForeignKey('self', null=True, blank=True, related_name='children', default=1)

def compute_metrics(self, shop_object, metric_queryset=None, rating_queryset=None)
    if(metric_queryset is None):
        metric_queryset = list([Metric.objects.all())
    if(rating_queryset is None):
        rating_queryset = list(Rating.objects.filter(shop_object=shop_object))

    for child in self.children.all():
        # do stuff
        child_score = child.compute_metrics(shop_object, metric_queryset, rating_queryset)

    # metrics_in_cat = metric_queryset.filter(category=self)
    metrics_in_cat = [m for m in metric_queryset if m.category==self]
    for metric in metrics_in_cat
        # do stuff
...